简体   繁体   中英

How to merge hash of hash without replacing first hash

Consider two hashes:

     h1 =  {a: 1, b: 2, d: {g: 7, h: 6}}
     h2 =  {a: 1, b: 2, d: {m: 4, n: 5}}

I was trying merge both hashes as:

h1.merge(h2)

Result: {:a=>1, :b=>2, :d=>{:m=>4, :n=>5}}

Can someone guide me to get a hash like:

{:a=>1, :b=>2, :d=>{:m=>4, :n=>5, :g=>7, :h=>6}} 

I had tried using deep_merge as suggested by some of other answers which didn't work.

Use Hash#merge with a block:

h1.merge(h2) do |k, v1, v2|
  v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.merge(v2) : v2
end

deep_merge works just fine, but it needs to be defined.

Plain Ruby

class Hash
  def deep_merge(h2)
    merge(h2) { |_, v1, v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? v1.deep_merge(v2) : v2 }
  end
end

h1 =  { a: 1, b: 2, d: { g: 7, h: 6 } }
h2 =  { a: 1, b: 2, d: { m: 4, n: 5 } }

h1.deep_merge(h2)
# => {:a=>1, :b=>2, :d=>{:g=>7, :h=>6, :m=>4, :n=>5}}

This method definition has the advantage of being recursive, and working with Hashes of any depth (see this example from yesterday).

Finally, if you want the exact same output as in your example, you need h2.merge(h1) :

h2.deep_merge(h1) #=> {:a=>1, :b=>2, :d=>{:g=>7, :h=>6, :m=>4, :n=>5}}
h1.deep_merge(h2) #=> {:a=>1, :b=>2, :d=>{:m=>4, :n=>5, :g=>7, :h=>6}}

Rails 3 & 4

Hash#deep_merge comes with Rails 3 & 4 .

If you use Rails, there's no need to define anything before using deep_merge

If you have Rails installed, and want to use deep_merge in plain Ruby scripts, you can use :

require 'active_support/core_ext/hash'
h1.deep_merge(h2)
#=> {:a=>1, :b=>2, :d=>{:g=>7, :h=>6, :m=>4, :n=>5}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM