1

次のような Ruby ハッシュの配列があるとします。

[{"lib1"=>"30"}, {"lib2"=>"30"}, {"lib9"=>"31"}, {"lib2"=>"31"}, {"lib3"=>"31"}, {"lib1"=>"32"}, {"lib2"=>"32"}, {"lib1"=>"33"}, {"lib3"=>"36"}, {"lib2"=>"36"}, {"lib1"=>"37"}]

次のようなハッシュを取得するにはどうすればよいですか。

{"lib1"=>[30,32,33,37], lib2=>[30,31,32,36], lib3=>[31,36], lib9=>[31]}
4

5 に答える 5

3
a = [{"lib1"=>"30"}, {"lib2"=>"30"}, {"lib9"=>"31"}, {"lib2"=>"31"}, {"lib3"=>"31"}, {"lib1"=>"32"}, {"lib2"=>"32"}, {"lib1"=>"33"}, {"lib3"=>"36"}, {"lib2"=>"36"}, {"lib1"=>"37"}]

a.map(&:to_a).flatten(1).each_with_object({}) do |(k, v), h|
  h[k] ||= []
  h[k] << v
end
#=> {"lib1"=>["30", "32", "33", "37"],
#    "lib2"=>["30", "31", "32", "36"],
#    "lib9"=>["31"],
#    "lib3"=>["31", "36"]}

または:

Hash[a.map(&:to_a).flatten(1).group_by(&:first).map { |k, v| [k, v.map(&:last)] }]

ファセットを使用したい場合、これはとてつもなく簡単になりcollateます:

a.inject(:collate)
于 2012-10-21T22:01:09.077 に答える
2
t = [{"lib1"=>"30"}, {"lib2"=>"30"}, {"lib9"=>"31"}, {"lib2"=>"31"},
  {"lib3"=>"31"}, {"lib1"=>"32"}, {"lib2"=>"32"}, {"lib1"=>"33"},
  {"lib3"=>"36"}, {"lib2"=>"36"}, {"lib1"=>"37"}]
result = {}

t.group_by { |x| x.keys.first }.each_pair do |k, v|
  result[k] = v.map { |e| e.values.first }
end

または、より純粋に機能的なバージョンと、非常に重要な 1 行 (結局のところ、Ruby です) に適した、一種のフィッティングの場合...

Hash[t.group_by { |x| x.keys[0] }.map { |k, v| [k, v.map { |e| e.values[0] }]}]
于 2012-10-21T22:28:37.840 に答える
2

Andrew の代わりに、flatten と to_a を回避し、ネストされた反復だけです。存在する場合、ソース配列内の要素ハッシュから複数のキーを収集します。

a.each_with_object({}) do |element,result|
  element.each do |k,v|
    (result[k] ||= []) << v.to_i
  end
end

1行にゴルフ:

a.each_with_object({}) {|e,r| e.each {|k,v| (r[k] ||= []) << v.to_i } }

to_a/flatten および group_by の回答には、ソースまたはソースの変換に対する複数回の反復が含まれるのに対し、このバージョンでは各ソース要素が 1 回だけ検査されることに注意してください。

Andrew は、Big-O アルゴリズムの複雑さの一定の要因は、実際には往々にして洗い流しであると良い点を指摘しています。これまでに提供された回答の簡単なベンチマークをまとめました(OPの例が示すように、値をfixnumにキャストするようにすべてを修正します)。私のネストされた反復アプローチは、OP のサンプル ソース データを使用すると多少 (23-45%) 高速であることが判明しました。

ruby 1.9.2p318 (2012-02-14 revision 34678) [x86_64-linux]
Rehearsal ------------------------------------------------------------
to_a_flat                  3.100000   0.000000   3.100000 (  3.105873)
to_a_flat_construct        4.060000   0.000000   4.060000 (  4.076938)
group_by_each              3.010000   0.000000   3.010000 (  3.015367)
group_by_each_construct    3.040000   0.000000   3.040000 (  3.050500)
nested_iter                2.300000   0.000000   2.300000 (  2.307776)
-------------------------------------------------- total: 15.510000sec

                               user     system      total        real
to_a_flat                  3.080000   0.000000   3.080000 (  3.096301)
to_a_flat_construct        4.050000   0.000000   4.050000 (  4.059409)
group_by_each              2.980000   0.000000   2.980000 (  2.997074)
group_by_each_construct    3.050000   0.000000   3.050000 (  3.057770)
nested_iter                2.300000   0.000000   2.300000 (  2.311855)
于 2012-10-21T22:37:29.563 に答える
-1

DigitalRoss のものに似ていますが、私は代わりにそれを行います:

array.group_by{|h| h.keys.first}.each{|_, a| a.map!{|h| h.values.first}}
于 2012-10-21T22:56:18.060 に答える