@Steenslag和@Stefan對我最初的回答提出了同樣的改進(雖然表達方式不同)。我已經編輯了我的答案,將其改進。
代碼
def doit(arr, n)
h = Hash.new(0)
arr.select { |e| n >= h[e] += 1 }
end
例
arr = [1,2,3,1,2,1,2,3]
n = 2
doit arr, n
#=> [1, 2, 3, 1, 2, 3]
說明
用於arr
和在實施例n
的值執行的步驟是爲f ollows。
h = Hash.new(0)
這是Hash::new的形式,它採用默認值,此處爲零。所有這一切意味着,如果上述定義沒有一個關鍵k
h
,則返回默認值:
h['cat'] #=> 0
這不會改變的哈希值。如果我們現在寫h[:a] = 1
(所以h=>{:a=>1}
),那麼h[:a]
返回1
,因爲h
現在有一個密鑰:a
。接着,通過enum
產生
enum = arr.reject
# => #<Enumerator: [1, 2, 3, 1, 2, 1, 2, 3]:reject>
的第一個值,並傳遞到塊,塊變量被分配它的值。
e = enum.next
#=> 1
塊計算現在執行
h[e] += 1
#=> h[e] = h[e] + 1
# h[e] = 0 + 1 = 1
所以現在
h #=> { 1=>1 }
和因爲
2 >= h[1]
#=> true
的arr
第一元件被選擇。
關於表達式h[1] = h[1] + 1
需要注意兩點。首先,因爲h
沒有密鑰1
,所以h[1]
在等號的右邊返回默認值零。其次,缺省值由方法Hash#[]使用,而不是由Hash#[]=(在等號左邊)使用。
enum
的第二個值現在傳遞給塊並執行類似的計算。
e = enum.next
#=> 2
h[e] += 1
#=> h[2] = h[2] + 1
# h[2] = 0 + 1
h #=> {1=>1, 2=>1}
2 >= h[2]
#=> true
所以第二個元素arr
也被選中。讓我們跳過被enum
產生的未來三個要素:
enum.next
#=> 3
enum.next
#=> 1
enum.next
#=> 2
此時
h = { 1=>2, 2=>2, 3=>1 }
和塊已經返回各自通過enum
產生的第一5
元素的truthy值。
接着,
e = enum.next
#=> 1
h[e] += 1
#=> h[1] = h[1] + 1
# h[1] = 2 + 1
h #=> {1=>3, 2=>2, 3=>1}
2 >= h[1]
#=> 2 >= 3 => false
所以這個值,1
未選中。其餘的計算是相似的。
'arr.select {| e | (h [e] + = 1)<= n}' – steenslag
'arr.reject {| e | n
Stefan
非常感謝,@steenslag和... –