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 15/02/2008, goodieboy [email protected] 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
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.
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
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 ?
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
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 ?
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.