I have a nested hash:
{
["X", 1, 2, 3]=> {
["X", "O", 2, 3]=> {
["X", "O", "X", 3]=>["X", "O", "X", "O"]
}
}
}
I want to merge a given nested hash:
{
["X", 1, 2, 3]=> {
["X", "O", 2, 3]=> {
["X", "O", 2, "X"] => ["X", "O", "O", "X"]
}
}
}
such that:
{
["X", 1, 2, 3]=> {
["X", "O", 2, 3]=> {
["X", "O", "X", 3]=>["X", "O", "X", "O"],
["X", "O", 2, "X"] => ["X", "O", "O", "X"]
}
}
}
What's the best way?
The hashes I'll be merging will have an equivalent key at an arbitrary depth of nested-ness. The value of the last nested hash will always be different from all the other hashes.
If you're sure that all the duplicate keys have values that are Hashes, you can use a recursive Hash#merge with block :
def deep_merge(h1,h2)
h1.merge(h2){|k,v1,v2| deep_merge(v1,v2) }
end
With your example :
{["X", 1, 2, 3]=>
{["X", "O", 2, 3]=>
{["X", "O", "X", 3]=>["X", "O", "X", "O"],
["X", "O", 2, "X"]=>["X", "O", "O", "X"]}}}
NOTE: This method doesn't work in the general case, and shouldn't be used for anything else than the structure defined in the question. It will fail for deep_merge({a:1},{a:2})
.
If you don't have information about the nested keys and values :
def deep_merge(h1,h2)
h1.merge(h2){|k,v1,v2| v1.is_a?(Hash) && v2.is_a?(Hash) ? deep_merge(v1,v2) : v2}
end
In case of a conflict with values that aren't both Hashes, the second value will overwrite the first one.
Both methods return a new hash, and do not modify either h1 or h2.
NOTE: This method is available in Rails.