2011-01-14 61 views
11

我不知道是否有在紅寶石做到這一點更規範的方式的項目的屬性的對象數組1.9大廈哈希通過分組基於

我有一大堆對象的數組,我想使用數組中每個對象的屬性將它們組成一個Hash。

非常簡單的例子:

> sh = {} 
=> {} 
> aers = %w(a b c d ab bc de abc) 
=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"] 
> aers.each do |aer| 
>  sh[aer.size] = [] if sh[aer.size].nil? 
>  sh[aer.size] << aer 
> end 
=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"] 
> sh 
=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 

我想這一點,但它的輸出是錯誤的(因爲你可以看到):

sh = Hash.new([]) 
=> {} 
> aers.each do |aer| 
>  sh[aer.size] << aer 
> end 
=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"] 
> sh 
=> {} 
+2

而你的代碼沒有按預期工作的原因說明如下:http://stackoverflow.com/questions/2698460/strange-ruby-behavior-when-using -hash-new和here:http://stackoverflow.com/questions/2552579/ruby-method-array-not-updating-the-array-in-hash(Ruby中很常見的陷阱)。 – 2011-01-14 15:23:51

回答

30

紅寶石已經預見你的需求,並且已經得到了你覆蓋着Enumerable#group_by

irb(main):001:0> aers = %w(a b c d ab bc de abc) 
#=> ["a", "b", "c", "d", "ab", "bc", "de", "abc"] 

irb(main):002:0> aers.group_by{ |s| s.size } 
#=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 

In R uby 1.9,你可以讓這甚至更短:

irb(main):003:0> aers.group_by(&:size) 
#=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 
+3

這就是爲什麼Ruby非常酷;它甚至在我們做之前就知道我們想要什麼。 – 2011-01-14 23:42:08

1

您還可以通過鏈接的方法......這可能僅僅是爲這個問題的學術興趣的做到這一點,但仍然是一個很好的技術熟悉。

irb(main):017:0> sh = {} 
=> {} 
irb(main):018:0> aers.collect{|k| k.size}.uniq!.each{|k| sh[k] = aers.select{|j| j.size == k}} 
=> [1, 2, 3] 
irb(main):019:0> sh 
=> {1=>["a", "b", "c", "d"], 2=>["ab", "bc", "de"], 3=>["abc"]} 
irb(main):020:0> 
3

Phrogz is correct,group_by is there for the taking。你的代碼包含了ruby的陷阱之一。

aers = %w(a b c d ab bc de abc) 
sh = Hash.new([]) # returns the _same_ array everytime the key is not found. 
# sh = Hash.new{|h,v| h[v] = []} # This one works 
p sh, sh.default 

aers.each do |aer| 
    sh[aer.size] << aer #modifies the default [] every time 
end 
p sh, sh.default 
p sh[5] 

輸出

{} 
[] 
{} 
["a", "b", "c", "d", "ab", "bc", "de", "abc"] 
["a", "b", "c", "d", "ab", "bc", "de", "abc"]