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}、ハッシュを作成する必要がありますか?常に1を追加するのではなく、nilケースをチェックするために本文を減らして変更する(そして、場合はゼロを割り当てる)ために、別のベースケースを指定する必要がありますか?nil

編集:

結局、コードを変更し、以下のメソッドを使用して、ネストされたハッシュをよりクリーンな方法で実現しました。

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
4

3 に答える 3

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

しかし、正直なところ、この配列を作成している場所に移動して、このような値を集約するように変更する方がおそらく良いでしょう。

于 2012-05-18T07:22:45.080 に答える
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}}
于 2012-05-18T07:25:59.407 に答える
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 -ハッシュは間違っています

于 2012-05-18T08:44:10.127 に答える