讓我們說我有每行號文件:如何組號碼分成不同的水桶紅寶石
0101
1010
1311
0101
1311
431
1010
431
420
最後,我將不得不與每個號碼的出現次數的哈希,在這種情況下, :
{0101 => 2, 1010 => 2, 1311 => 2, 431 => 2, 420 => 1}
我該怎麼做到這一點?
讓我們說我有每行號文件:如何組號碼分成不同的水桶紅寶石
0101
1010
1311
0101
1311
431
1010
431
420
最後,我將不得不與每個號碼的出現次數的哈希,在這種情況下, :
{0101 => 2, 1010 => 2, 1311 => 2, 431 => 2, 420 => 1}
我該怎麼做到這一點?
簡單的一行,給定一個數組items
:
items.inject(Hash.new(0)) {|hash, item| hash[item] += 1; hash}
工作原理:
Hash.new(0)
創建一個新的Hash,其中訪問未定義的鍵在一個數組返回0
inject(foo)
迭代與給定的塊。對於第一次迭代,它通過foo
,並在進一步的迭代中傳遞最後一次迭代的返回值。
另一種方式來寫這將是:
hash = Hash.new(0)
items.each {|item| hash[item] += 1}
ID = -> x { x } # Why is the identity function not in the core lib?
f = <<-HERE
0101
1010
1311
0101
1311
431
1010
431
420
HERE
Hash[f.lines.map(&:to_i).group_by(&ID).map {|n, ns| [n, ns.size] }]
# { 101 => 2, 1010 => 2, 1311 => 2, 431 => 2, 420 => 1 }
您只需組使用Enumerable#group_by
自己的數字,它給你像
{ 101 => [101, 101], 420 => [420] }
然後你Enumerable#map
值陣列到它們的長度,即[101, 101]
變成2
。然後使用Hash::[]
將其轉換回Hash
。
但是,如果您願意使用第三方庫,它會變得更加微不足道,因爲如果您使用MultiSet
數據結構,答案會自然而然地出現。 (A MultiSet
就像一個Set
,除了一個項目可以多次添加和MultiSet
將保留的項目是如何經常地加入 –這是你想要什麼計數)。
require 'multiset' # Google for it, it's so old that it isn't available as a Gem
Multiset[*f.lines.map(&:to_i)]
# => #<Multiset:#2 101, #2 1010, #2 1311, #2 431, #1 420>
是的,這是它。
這是關於使用正確數據結構的美妙之處:您的算法變得非常簡單。或者,在這種特殊情況下,算法消失。
我已經寫了更多關於使用MultiSet
局長在
group_by
例子一樣。)這是基本相同,Chuck的,但是當你創建一個數組或哈希,「each_with_object」將使它比'inject'稍微簡單一些,因爲您不必在塊中編寫最終數組或散列。
items.each_with_object(Hash.new(0)) {|item, hash| hash[item] += 1}
我想我發現與不同的措詞對同一問題:) [計數紅寶石陣列重複的元素](http://stackoverflow.com/questions/569694/count-duplicate-elements-in-ruby-array ) – Matchu 2010-11-29 01:17:24
:)多數民衆贊成在偉大的。謝謝。 – josh 2010-11-29 01:21:19
僅供參考:如果碰巧是Rails,則可以使用Enumerable#group_by。請參閱http://api.rubyonrails.org/classes/Enumerable.html#method-i-group_by – 2010-11-29 16:36:53