ironsand
ironsand

Reputation: 15141

How to merge two hashes without losing values

I have two hashes like these.

a = {foo: {first: 1}, bar: {first: 2}}
b = {foo: {second: 3}, bar: {second: 4}}

And I expected as a result of a.merge b like this.

{foo: {first: 1, second: 3}, bar: {first: 2, second: 4}}

But a.merge b returns {:foo=>{:second=>3}, :bar=>{:second=>4}}.

How can I merge two hashes without losing values?

Upvotes: 2

Views: 1259

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110665

You should use the form of Hash#merge that takes a block that determines the value associated with every key that is present in both hashes.

Code

def merge_em(a,b)    
  a.merge(b) { |k,va,vb| va.merge(vb) }
end

Example

a = {foo: {first:  1}, bar: {first:  2}}
b = {foo: {second: 3}, bar: {second: 4}}

merge_em(a,b)
  #=> {:foo=>{:first=>1, :second=>3}, :bar=>{:first=>2, :second=>4}}

Explanation

Here the block variables are as follows:

`k` : the key
`va`: the value for key `k` in the merged hash (`a`)
`vb`: the value for key `k` in the hash being merged (`b`)

We want the value for key k to be simply:

va.merge(vb)

Upvotes: 0

bjhaid
bjhaid

Reputation: 9752

if the format of your hash would always look like you specified the below would work:

a = {foo: {first: 1}, bar: {first: 2}}
b = {foo: {second: 3}, bar: {second: 4}}
a.each_with_object(b) { |(k,v),x| x[k].merge!(v) }
# => {:foo=>{:second=>3, :first=>1}, :bar=>{:second=>4, :first=>2}}

Otherwise use ActiveSupport's deep_merge!

Upvotes: 5

Related Questions