From: Jimmy Kofler Date: 2008-02-22T00:52:16+09:00 Subject: Re: recursive merge for hash > Stefan Rusterholz wrote: > Jimmy Kofler 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 ? >> >> 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. -- Posted via http://www.ruby-forum.com/.