[英]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.