繁体   English   中英

过滤包含整数和字符串的数组

[英]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'])

从理论上讲,我的代码是有效的,因为如果我用单词替换itemsl.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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM