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
on 2008-02-15 16:37
on 2008-02-15 16:49
On 15/02/2008, goodieboy <goodieBoy@gmail.com> 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
on 2008-02-15 16:57
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
on 2008-02-16 14:51
> 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.
on 2008-02-19 21:51
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
on 2008-02-21 16:52
> 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.
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.