[英]Filter an Array containing Integers and Strings
我试图制作一个方法来过滤一个包含正整数和字符串的数组只留下整数,但奇怪的是我的代码不起作用。
def filter_list(l)
l.map { |items| items.is_a?(Integer) ? items : l.delete(items) }
end
filter_list([1,2,'a','b'])
从理论上讲,我的代码是有效的,因为如果我用单词替换items
和l.delete(items)
为'true'和'false'整数和字符串正在被正确替换返回
[true, true, false, false]
但是,保留items : l.delete(items)
它会归还给我
[1, 2, "a"] or sometimes [1, 2, "b"]
所以只删除一个。 如何更改我的方法只返回整数?
您的代码不起作用,因为您在迭代同一个数组时使用l.delete
从数组中删除元素。
想象一下,你走了一个包含4个元素的数组,同时有人改变了数组中元素的数量及其位置。
我想你正在寻找Array#select
:
array = [1, 2, 'a', 'b']
array.select { |element| element.is_a?(Integer) }
#=> [1, 2]
您的问题是,如果您的项目不是整数,那么您正在改变数组map
ping。
当你的map
首次访问元素'a'
它会调用l.delete('a')
(返回'a'
)。 这意味着'l'
不再是您的map
初始数组。 而不是最初的[1, 2, 'a', 'b']
你的数组l
现在包含[1, 2, 'b']
。
我不确定map
的确切实现,但我想现在数组被改变了,只包含了三个而不是四个元素, map
不会查看数组中的最后一个'b'
。 假设你有一个数组a = [1, 2, 'a', 'b']
。
第一次调用filter_list(a)
它返回[1, 2, 'a']
。 如果你现在打印a
你将得到你改变的数组的内容: [1, 2, 'b']
。 为什么这与函数调用的结果不同? 因为map会创建一个包含map
返回值的新数组(而delete
返回已删除的值,在第一次调用中会导致'a'
)。 但作为'a'
是从我们的阵列中删除a
我们的阵列的结果是[1, 2, 'b']
下次调用filter_list(a)
它会map
到[1, 2, 'b']
。 这导致第二次delete
调用,返回'b'
。 因此map
返回一个包含[1, 2, 'b']
的新数组。 在第二次调用filter_list
您再次更改了输入数组,以便我们的数组a
现在只包含[1, 2]
。
如果调用filter_list(a)
再一次,你会得到[1, 2]
结果和a
会没有离开数组中的字符串被删除不会再改变。
您应该始终小心改变输入数据,因为它可能具有(并且在这种情况下)有意外的副作用。
更好的替代方法是使用Ruby的select
方法(这是一种过滤方法)( https://ruby-doc.org/core-2.4.0/Array.html#method-i-select ):
a = [1, 2, 'a', 'b']
a.select { |element| element.is_a?(Integer) }
尝试这个:
a = [1, 2, 3.4, 'a', 'b', [:c], { d: 1 }]
a.grep Integer #=> [1, 2]
a.grep Float #=> [3.4]
a.grep Numeric #=> [1, 2, 3.4]
a.grep String #=> ['a', 'b']
a.grep Array #=> [[:c]]
a.grep Hash #=> [{ :d => 1 }]
请参阅Enumerable#grep 。
.delete(items)
返回items
,其被映射到阵列。
在你的控制台中
arr = [1,2,'a','b']
arr.delete('b')
# => 'b'
arr
# => [1, 2, 'a']
因此,删除也有效,但它返回已删除的元素,因此无法映射,因为.map
创建一个块返回的任何值的数组。
如果你想使用.delete
那么,
def filter_list(l)
l.dup.each{ |e| l.delete(e) unless e.is_a?(Integer) }
l
end
这是效率低下的,试试吧
l.select { |items| items.is_a?(Integer) }
如果你想要一个特定类的实例, grep
是正确的答案。
如果要按类对元素进行分组,可以编写:
strings, integers = [1,2,'a','b'].group_by(&:class).values_at(String, Fixnum)
strings
# => ["a", "b"]
integers
# => [1, 2]
如果您仍想使用您编写的代码,您可以执行以下操作:
def filter_list(l)
i = l.length
while i > 0
l.map { |items| items.is_a?(Integer) ? items : l.delete(items) }
i -= 1
end
l
end
filter_list([1, 2, 'a', 'b', 3, 'duh', 'isitover?']) # will return [1, 2, 3]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.