要散列的哈希数组

例如,我有一个单散列数组

a = [{a: :b}, {c: :d}]

把它转换成这个的最好方法是什么?

{a: :b, c: :d}
36324 次浏览

You may use

a.reduce Hash.new, :merge

which directly yields

{:a=>:b, :c=>:d}

Note that in case of collisions the order is important. Latter hashes override previous mappings, see e.g.:

[{a: :b}, {c: :d}, {e: :f, a: :g}].reduce Hash.new, :merge   # {:a=>:g, :c=>:d, :e=>:f}

These two are equivalent (reduce/inject are the same method):

total_hash = hs.reduce({}) { |acc_hash, hash| acc_hash.merge(hash) }
total_hash = hs.reduce({}, :merge)

Note that Hash#merge creates a new hash on each iteration, which may be a problem if you are building a big one. In that case, use update instead:

total_hash = hs.reduce({}, :update)

Alternatively, you can convert the hashes to pairs and then build the final hash:

total_hash = hs.flat_map(&:to_a).to_h

You can use .inject:

a.inject(:merge)
#=> {:a=>:b, :c=>:d}

Demonstration

Which initiates a new hash on each iteration from the two merged. To avoid this, you can use destructive :merge!( or :update, which is the same):

a.inject(:merge!)
#=> {:a=>:b, :c=>:d}

Demonstration

Try this

a.inject({}){|acc, hash| acc.merge(hash)} #=> {:a=>:b, :c=>:d}

Just use

a.reduce(:merge)
#=> {:a=>:b, :c=>:d}

I came across this answer and I wanted to compare the two options in terms of performance to see which one is better:

  1. a.reduce Hash.new, :merge
  2. a.inject(:merge)

using the ruby benchmark module, it turns out that option (2) a.inject(:merge) is faster.

code used for comparison:

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

the results were

       user     system      total        real
reduce  0.125098   0.003690   0.128788 (  0.129617)
inject  0.078262   0.001439   0.079701 (  0.080383)

You can transform it to array [[:a, :b]] and after that translate everything to hash {: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}