たとえば、私は単一のハッシュの配列を持っています
a = [{a: :b}, {c: :d}]
これに変換する最良の方法は何ですか?
{a: :b, c: :d}
あなたは使用することができます
a.reduce Hash.new, :merge
これは直接
{:a=>:b, :c=>:d}
衝突の場合、順序が重要であることに注意してください。後のハッシュは以前のマッピングをオーバーライドします。例を参照してください。
[{a: :b}, {c: :d}, {e: :f, a: :g}].reduce Hash.new, :merge # {:a=>:g, :c=>:d, :e=>:f}
あなたが使用することができます.inject
:
a.inject(:merge)
#=> {:a=>:b, :c=>:d}
これは、マージされた2つの反復からの各反復で新しいハッシュを開始します。これを回避するには、破壊的:merge!
(または:update
、同じ)を使用できます。
a.inject(:merge!)
#=> {:a=>:b, :c=>:d}
この二つ:
total_hash = hs.reduce({}) { |acc_hash, hash| acc_hash.merge(hash) }
total_hash = hs.reduce({}, :merge)
反復ごとに新しいハッシュが作成されることに注意してくださいHash#merge
。これは、大きなハッシュを作成する場合に問題になる可能性があります。その場合は、update
代わりに次を使用してください。
total_hash = hs.reduce({}, :update)
別のアプローチは、ハッシュをペアに変換してから、最終的なハッシュを作成することです。
total_hash = hs.flat_map(&:to_a).to_h
私はこの答えに出くわし、パフォーマンスの観点から2つのオプションを比較して、どちらが優れているかを確認したいと思いました。
a.reduce Hash.new, :merge
a.inject(:merge)
rubyベンチマークモジュールを使用すると、オプション(2)a.inject(:merge)
の方が高速であることがわかります。
比較に使用されるコード:
require 'benchmark'
input = [{b: "c"}, {e: "f"}, {h: "i"}, {k: "l"}]
n = 50_000
Benchmark.bm do |benchmark|
benchmark.report("reduce") do
n.times do
input.reduce Hash.new, :merge
end
end
benchmark.report("inject") do
n.times do
input.inject(:merge)
end
end
end
結果は
user system total real
reduce 0.125098 0.003690 0.128788 ( 0.129617)
inject 0.078262 0.001439 0.079701 ( 0.080383)
使用するだけ
a.reduce(:merge)
#=> {:a=>:b, :c=>:d}
これを試して
a.inject({}){|acc, hash| acc.merge(hash)} #=> {:a=>:b, :c=>:d}
あなたはそれを配列[[:a, :b]]
に変換し、その後すべてをハッシュに変換することができます{:a=>:b}
# it works like [[:a, :b]].to_h => {:a=>:b}
[{a: :b}, {c: :d}].map { |hash| hash.to_a.flatten }.to_h
# => {:a=>:b, :c=>:d}