Например, у меня есть массив одиночных хэшей
a = [{a: :b}, {c: :d}]
Каков наилучший способ превратить его в это?
{a: :b, c: :d}
Например, у меня есть массив одиночных хэшей
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}
Что инициирует новый хэш на каждой итерации из двух объединенных. Чтобы этого избежать, вы можете использовать деструктивные :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
Попробуй это
a.inject({}){|acc, hash| acc.merge(hash)} #=> {:a=>:b, :c=>:d}
Просто используйте
a.reduce(:merge)
#=> {:a=>:b, :c=>:d}
Я наткнулся на этот ответ и хотел сравнить два варианта с точки зрения производительности, чтобы увидеть, какой из них лучше:
a.reduce Hash.new, :merge
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)
Вы можете преобразовать его в массив [[: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}