簡體   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