2012-05-18 171 views
1

列表我有一組類別和它們的值存儲爲散列的列表:創建嵌套的哈希值從哈希值的紅寶石

r = [{:A => :X}, {:A => :Y}, {:B => :X}, {:A => :X}, {:A => :Z}, {:A => :X}, 
    {:A => :X}, {:B => :Z}, {:C => :X}, {:C => :Y}, {:B => :X}, {:C => :Y}, 
    {:C => :Y}] 

我想獲得再加上每個值的計數其類別作爲這樣的散列:

{:A => {:X => 4, :Y => 1, :Z => 1}, 
:B => {:X => 2, :Z => 1}, 
:C => {:X => 1, :Y => 3}} 

我該如何有效地做到這一點?

這是我迄今(它返回不一致的值):

r.reduce(Hash.new(Hash.new(0))) do |memo, x| 
    memo[x.keys.first][x.values.first] += 1 
    memo 
end 

我應該首先計算特定{:cat => :val} S的所有實例的計數,然後創建哈希?我是否應該給出一個不同的基本案例來減少和更改身體檢查nil個案(並在nil時指定零),而不是始終添加1?

編輯:

我最終改變我的代碼,並使用下面的方法有實現嵌套散列的更清潔的方式:

r.map do |x| 
    [x.keys.first, x.values.last] 
end.reduce({}) do |memo, x| 
    memo[x.first] = Hash.new(0) if memo[x.first].nil? 
    memo[x.first][x.last] += 1 
    memo 
end 

回答

0

你的代碼的問題是:備忘錄未持有價值。 使用一個變量外循環保存值將是確定的:

memo = Hash.new {|h,k| h[k] = Hash.new {|hh, kk| hh[kk] = 0 } } 

r.each do |x| 
    memo[x.keys.first][x.values.first] += 1 
end 

p memo 

而且更重要的是,它不會工作到初始化嵌套哈希裏面直接像這樣的哈希:

# NOT RIGHT 
memo = Hash.new(Hash.new(0)) 
memo = Hash.new({}) 

以下是有關設置默認值問題的更多鏈接的鏈接: http://www.themomorohoax.com/2008/12/31/why-setting-the-default-value-of-a-hash-to-be-a-hash-is-wrong

+0

謝謝,這解釋了我遇到的問題。 – maksim

0

不知道什麼是「不一致的值」的意思,但你的問題是你注入不記得它的結果

r.each_with_object(Hash.new { |h, k| h[k] = Hash.new 0 }) do |individual, consolidated| 
    individual.each do |key, value| 
    consolidated[key][value] += 1 
    end 
end 

但說實話哈希,它很可能是更好的只是去,無論你正在做這個數組和將其更改爲像這樣的聚合值。使用一些方便的抽象 - 沒有需要從facets重塑wheel-

+0

「不一致的值」意味着在給定不同的密鑰時,散列不會記住或返回正確的值。 – maksim

0

功能的方法:

require 'facets'  
r.map_by { |h| h.to_a }.mash { |k, vs| [k, vs.frequency] } 
#=> {:A=>{:X=>4, :Y=>1, :Z=>1}, :B=>{:X=>2, :Z=>1}, :C=>{:X=>1, :Y=>3}}