# Recursive merge for hash

**URL:** <https://www.ruby-forum.com/t/recursive-merge-for-hash/129226>\
**Category:** Ruby\
**Created:** [February 15, 2008, 4:37pm UTC](https://www.ruby-forum.com/t/recursive-merge-for-hash/129226 "2008-02-15T16:37:51Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 15, 2008, 4:37pm UTC](https://www.ruby-forum.com/t/recursive-merge-for-hash/129226/1 "2008-02-15T16:37:51Z")

</div>

Hi,

Does anyone know of a good recursive merge method for Hashes? I’d like  
to be able to do something like:

new\_h = first.merge\_r(second).merge\_r(third)

… everything would be a copy, and hashes applied later in the  
sequence override the previous finally, returning a completely new  
hash… is there something out there like this?

Thanks,  
Matt

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 15, 2008, 4:49pm UTC](https://www.ruby-forum.com/t/recursive-merge-for-hash/129226/2 "2008-02-15T16:49:03Z")

</div>

On 15/02/2008, goodieboy [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Hi,
> 
> Does anyone know of a good recursive merge method for Hashes? I’d like  
> to be able to do something like:
> 
> new\_h = first.merge\_r(second).merge\_r(third)
> 
> … everything would be a copy, and hashes applied later in the  
> sequence override the previous finally, returning a completely new  
> hash… is there something out there like this?

new\_h = first.merge(second).merge(third)

Farrel

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 16, 2008, 2:51pm UTC](https://www.ruby-forum.com/t/recursive-merge-for-hash/129226/3 "2008-02-16T14:51:39Z")

</div>

> M.W. Mitchell wrote:  
> Thanks. But the only problem with that is, the overriding hash will  
> completely destroy _all_ of the values in the original. So if I want  
> to just override one value, I get only one value. In this example,  
> “Sam” is lost:
> 
> first = {  
> :data=\>{  
> :name=\>{  
> :first=\>‘Sam’,  
> :middle=\>‘I’,  
> :last=\>‘am’  
> }  
> }  
> }
> 
> second={  
> :data=\>{  
> :name=\>{  
> :middle=\>‘you’,  
> :last=\>‘are’  
> }  
> }  
> }  
> all\_new = first.merge(second)
> 
> puts all\_new.inspect

How about Hash#deep\_merge, [http://snippets.dzone.com/posts/show/4706](http://snippets.dzone.com/posts/show/4706) ?

Cheers,  
j.k.

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 15, 2008, 4:57pm UTC](https://www.ruby-forum.com/t/recursive-merge-for-hash/129226/4 "2008-02-15T16:57:16Z")

</div>

Thanks. But the only problem with that is, the overriding hash will  
completely destroy _all_ of the values in the original. So if I want  
to just override one value, I get only one value. In this example,  
“Sam” is lost:

first = {  
:data=\>{  
:name=\>{  
:first=\>‘Sam’,  
:middle=\>‘I’,  
:last=\>‘am’  
}  
}  
}

second={  
:data=\>{  
:name=\>{  
:middle=\>‘you’,  
:last=\>‘are’  
}  
}  
}  
all\_new = first.merge(second)

puts all\_new.inspect

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 19, 2008, 9:51pm UTC](https://www.ruby-forum.com/t/recursive-merge-for-hash/129226/5 "2008-02-19T21:51:51Z")

</div>

Jimmy K. wrote:

> > M.W. Mitchell wrote:  
> > Thanks. But the only problem with that is, the overriding hash will  
> > completely destroy _all_ of the values in the original. So if I want  
> > to just override one value, I get only one value. In this example,  
> > “Sam” is lost:
> > 
> > first = {  
> > :data=\>{  
> > :name=\>{  
> > :first=\>‘Sam’,  
> > :middle=\>‘I’,  
> > :last=\>‘am’  
> > }  
> > }  
> > }
> > 
> > second={  
> > :data=\>{  
> > :name=\>{  
> > :middle=\>‘you’,  
> > :last=\>‘are’  
> > }  
> > }  
> > }  
> > all\_new = first.merge(second)
> > 
> > puts all\_new.inspect
> 
> How about Hash#deep\_merge, [http://snippets.dzone.com/posts/show/4706](http://snippets.dzone.com/posts/show/4706) ?
> 
> Cheers,  
> j.k.

The question came up on IRC recently and I remembered this post. But I  
wonder why the snippet does it in such a complicated way. Alternative:  
merger = proc { |key,v1,v2| Hash === v1 && Hash === v2 ? v1.merge(v2,  
&merger) : v2 }  
first.merge(second, &merger)

Regards  
Stefan

---

<div class="post-metadata">

**Author:** ![goodieboy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/ecc23a/32.png) [@goodieboy](https://www.ruby-forum.com/u/goodieboy)\
**Post date:** [February 21, 2008, 4:52pm UTC](https://www.ruby-forum.com/t/recursive-merge-for-hash/129226/6 "2008-02-21T16:52:23Z")

</div>

> Stefan R. wrote:  
> Jimmy K. wrote:
> 
> > > M.W. Mitchell wrote:  
> > > Thanks. But the only problem with that is, the overriding hash will  
> > > completely destroy _all_ of the values in the original. So if I want  
> > > to just override one value, I get only one value. In this example,  
> > > “Sam” is lost:
> > > 
> > > first = {  
> > > :data=\>{  
> > > :name=\>{  
> > > :first=\>‘Sam’,  
> > > :middle=\>‘I’,  
> > > :last=\>‘am’  
> > > }  
> > > }  
> > > }
> > > 
> > > second={  
> > > :data=\>{  
> > > :name=\>{  
> > > :middle=\>‘you’,  
> > > :last=\>‘are’  
> > > }  
> > > }  
> > > }  
> > > all\_new = first.merge(second)
> > > 
> > > puts all\_new.inspect
> > 
> > How about Hash#deep\_merge, [http://snippets.dzone.com/posts/show/4706](http://snippets.dzone.com/posts/show/4706) ?
> > 
> > Cheers,  
> > j.k.
> 
> The question came up on IRC recently and I remembered this post. But I  
> wonder why the snippet does it in such a complicated way. Alternative:  
> merger = proc { |key,v1,v2| Hash === v1 && Hash === v2 ? v1.merge(v2,  
> &merger) : v2 }  
> first.merge(second, &merger)
> 
> Regards  
> Stefan

Well, maybe it’s a bit easier to modify or extend the verbose version.

For example:

class Hash  
def keep\_merge(hash)  
target = dup  
hash.keys.each do |key|  
if hash[key].is\_a? Hash and self[key].is\_a? Hash  
target[key] = target[key].keep\_merge(hash[key])  
next  
end  
#target[key] = hash[key]  
target.update(hash) { |key, \*values| values.flatten.uniq }  
end  
target  
end  
end

first = {  
:data=\>{  
:name=\>{  
:first=\>‘Sam’,  
:middle=\>‘I’,  
:last=\>‘am’  
}  
}  
}

second={  
:data=\>{  
:name=\>{  
:middle=\>‘you’,  
:last=\>‘are’  
}  
}  
}

p first.keep\_merge(second)  
#=\> {:data=\>{:name=\>{:first=\>“Sam”, :middle=\>[“I”, “you”],  
:last=\>[“am”, “are”]}}}

Anyway, a nice refactoring example!

Cheers,  
j. k.
