Par exemple, j'ai un tableau de hachages simples
a = [{a: :b}, {c: :d}]
Quel est le meilleur moyen de le convertir en cela?
{a: :b, c: :d}
Vous pouvez utiliser
a.reduce Hash.new, :merge
qui donne directement
{:a=>:b, :c=>:d}
Notez qu'en cas de collision, l'ordre est important. Les hachages récents annulent les mappages précédents, voir par exemple:
[{a: :b}, {c: :d}, {e: :f, a: :g}].reduce Hash.new, :merge # {:a=>:g, :c=>:d, :e=>:f}
Vous pouvez utiliser .inject
:
a.inject(:merge)
#=> {:a=>:b, :c=>:d}
Ce qui initie un nouveau hachage à chaque itération parmi les deux fusionnés. Pour éviter cela, vous pouvez utiliser le :merge!
destructeur (ou le :update
, qui est identique):
a.inject(:merge!)
#=> {:a=>:b, :c=>:d}
Ces deux:
total_hash = hs.reduce({}) { |acc_hash, hash| acc_hash.merge(hash) }
total_hash = hs.reduce({}, :merge)
Notez que Hash#merge
crée un nouveau hachage à chaque itération, ce qui peut poser problème si vous construisez un gros hachage. Dans ce cas, utilisez update
à la place:
total_hash = hs.reduce({}, :update)
Une autre approche serait de convertir les hachages en paires, puis de construire le hachage final:
total_hash = hs.flat_map(&:to_a).to_h
Vous pouvez le transformer en tableau [[:a, :b]]
et ensuite traduire tout en 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}
Je suis tombé sur cette réponse et je voulais comparer les deux options en termes de performances pour voir laquelle est la meilleure:
a.reduce Hash.new, :merge
a.inject(:merge)
en utilisant le module de référence Ruby, il s’avère que l’option (2) a.inject(:merge)
est plus rapide.
code utilisé pour la comparaison:
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
les résultats ont été
user system total real
reduce 0.125098 0.003690 0.128788 ( 0.129617)
inject 0.078262 0.001439 0.079701 ( 0.080383)
Essaye ça
a.inject({}){|acc, hash| acc.merge(hash)} #=> {:a=>:b, :c=>:d}
Juste utiliser
a.reduce(:merge)
#=> {:a=>:b, :c=>:d}