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

时间:2017-05-20 10:37:47

标签: arrays ruby

我正在尝试创建一个方法来过滤包含正整数和字符串的数组,只留下整数,但奇怪的是我的代码不起作用。

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"]

所以只删除一个。如何改变我的方法只返回整数?

6 个答案:

答案 0 :(得分:4)

您的代码不起作用,因为在迭代同一个数组时,使用l.delete从数组中删除元素。

想象一下,你走了一个包含4个元素的数组,同时,有人会改变数组中元素的数量及其位置。

我认为您正在寻找Array#select

array = [1, 2, 'a', 'b']
array.select { |element| element.is_a?(Integer) }
#=> [1, 2]

答案 1 :(得分:1)

如果您的项目不是整数,那么您的问题是您正在更改数组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],结果会得到aselect将不会再次更改,因为数组中没有要删除的字符串。

您应该始终小心改变您的输入数据,因为它可能具有(并且在这种情况下)有意外的副作用。

更好的替代方案是使用Ruby的a = [1, 2, 'a', 'b'] a.select { |element| element.is_a?(Integer) } 方法(这是一种过滤方法)(https://ruby-doc.org/core-2.4.0/Array.html#method-i-select):

Public Class WorkStationDetails<br><br>
    Property CountryId As Integer<br>
    Property CountryName As String<br>
    Property TotalWrkStn As Integer<br>
    Property ExistingWrkStn As Integer<br>
    Property RemainingWrkStn As Integer<br><br>
End Class

Dim WrkStnDtl As List(Of WorkStationDetails)
Dim FilterWrkStnDtl As List(Of WorkStationDetails)
Dim Numbers As String()

Numbers = "1,5,6,2,9".Split(",")

  For i As Integer = 0 To Numbers.Length - 1
      FilterWrkStnDtl.AddRange(WrkStnDtl.FindAll(Function(p) (p.CountryId = Numbers(i))))
  Next

答案 2 :(得分:1)

试试这个:

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

答案 3 :(得分:0)

.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) }

答案 4 :(得分:0)

如果您想要一个特定类的实例,

grep是正确的答案。

如果要按类对元素进行分组,可以写:

strings, integers = [1,2,'a','b'].group_by(&:class).values_at(String, Fixnum)
strings
# => ["a", "b"]
integers
# => [1, 2]

答案 5 :(得分:0)

如果您仍想使用您编写的代码,您可以执行以下操作:

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]