2012-06-08 3 views
54

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

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

Что лучший способ, чтобы преобразовать его в это?

{a: :b, c: :d} 

ответ

94

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

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} 
+25

'Hash.new', или как друзья, как в позвоните ему, '{}' :-) Насколько мне нравится чистое функциональное решение, обратите внимание, что 'merge' создаст новый хэш на каждой итерации; вместо этого мы можем использовать 'update' (это не испортит хеши ввода, это важный момент):' hs.reduce ({},: update) ' – tokland

+0

Красиво сделано – Aeramor

+0

@tokland, опубликуйте свой комментарий как отдельный ответ - он должен получить больше видимости – Jason

19

Эти две строки эквивалентны:

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 
18

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

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

Demonstration

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

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

Demonstration

0

Попробуйте

a.inject({}){|acc, hash| acc.merge(hash)} #=> {:a=>:b, :c=>:d} 
Смежные вопросы