if want recursively merge 2 hashes, can following function:
def recursive_merge(a,b) a.merge(b) {|key,a_item,b_item| recursive_merge(a_item,b_item) } end
this works great, in can do:
ahash = recursive_merge(ahash,newhash)
but i'd add self-updating style method similar merge!
. can add in returning function:
class hash def recursive_merge(newhash) self.merge { |key,a_item,b_item| a_item.recursive_merge(b_item) } end end
but not sure how re-create bang
function updates original object without association.
class hash def recursive_merge!(newhash) self.merge { |key,a_item,b_item| a_item.recursive_merge(b_item) } # how set "self" new hash? end end
edit example per comments.
h={:a=>{:b => "1"} h.recursive_merge!({:a=>{:c=>"2"}) => {:a=>{:b=>"1", :c="2"}}
the regular merge results in :b=>"1"
being overwritten :c="2"
use merge!
rather attempt update self
. don't believe makes sense use merge! anywhere @ top level, wouldn't call bang version recursively. instead, use merge! @ top level, , call non-bang method recursively.
it may wise check both values being merged indeed hashes, otherwise may exception if attempt recursive_merge on non-hash object.
#!/usr/bin/env ruby class hash def recursive_merge(other) self.merge(other) { |key, value1, value2| value1.is_a?(hash) && value2.is_a?(hash) ? value1.recursive_merge(value2) : value2} end def recursive_merge!(other) self.merge!(other) { |key, value1, value2| value1.is_a?(hash) && value2.is_a?(hash) ? value1.recursive_merge(value2) : value2} end end h1 = { a: { b:1, c:2 }, d:1 } h2 = { a: { b:2, d:4 }, d:2 } h3 = { d: { b:1, c:2 } } p h1.recursive_merge(h2) # => {:a=>{:b=>2, :c=>2, :d=>4}, :d=>2} p h1.recursive_merge(h3) # => {:a=>{:b=>1, :c=>2}, :d=>{:b=>1, :c=>2}} p h1.recursive_merge!(h2) # => {:a=>{:b=>2, :c=>2, :d=>4}, :d=>2} p h1 # => {:a=>{:b=>2, :c=>2, :d=>4}, :d=>2}
if have specific reason merge in place, possibly speed, can experiment making second function call recursively, rather delegate recursion first function. aware may produce unintended side effects if hashes store shared objects.
example:
h1 = { a:1, b:2 } h2 = { a:5, c:9 } h3 = { a:h1, b:h2 } h4 = { a:h2, c:h1 } p h3.recursive_merge!(h4) # making recursive calls recursive_merge # => {:a=>{:a=>5, :b=>2, :c=>9}, :b=>{:a=>5, :c=>9}, :c=>{:a=>1, :b=>2}} # making recursive calls recursive_merge! # => {:a=>{:a=>5, :b=>2, :c=>9}, :b=>{:a=>5, :c=>9}, :c=>{:a=>5, :b=>2, :c=>9}}
as can see, second (shared) copy of h1 stored under key :c updated reflect merge of h1 , h2 under key :a. may surprising , unwanted. hence why recommend using recursive_merge
recursion, , not recursive_merge!
.
Comments
Post a Comment