Массив хешей в хэш

Например, у меня есть массив одиночных хэшей

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

Каков наилучший способ превратить его в это?

{a: :b, c: :d}

Ответ 1

Вы можете использовать

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}

Ответ 2

Вы можете использовать .inject:

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

демонстрация

Что инициирует новый хэш на каждой итерации из двух объединенных. Чтобы этого избежать, вы можете использовать деструктивные :merge! (или :update, то же самое):

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

демонстрация

Ответ 3

Эти двое:

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

Ответ 4

Попробуй это

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

Ответ 5

Просто используйте

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

Ответ 6

Я наткнулся на этот ответ и хотел сравнить два варианта с точки зрения производительности, чтобы увидеть, какой из них лучше:

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

с помощью модуля тестирования ruby получается, что option (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)

Ответ 7

Вы можете преобразовать его в массив [[: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}