2012-01-11 76 views
1

我想采取这样的形式的两个散列:合并同名阵列,红宝石哈希

hash_1 = {:a=>{:b=>3, :c=>{:stuff1=>[{:d=>1, :e=>2}, {:d=>4, :e=>2}], :stuff2=>[{:f=>33, :g=>44}, {:f=>55, :g=>66}], :h=>4}}} 

hash_2 = {:a=>{:b=>3, :c=>{:stuff1=>[{:d=>8, :e=>5}, {:d=>7, :e=>5}], :stuff2=>[{:f=>45, :g=>89}, {:f=>78, :g=>67}], :h=>4}}} 

而且把它恢复(注意:stuff1:stuff2加在一起):

result = {:a=>{:b=>3, :c=>{:stuff1=>[{:d=>1, :e=>2}, {:d=>4, :e=>2}, {:d=>8, :e=>5}, {:d=>7, :e=>5}], :stuff2=>[{:f=>33, :g=>44}, {:f=>55, :g=>66}, {:f=>45, :g=>89}, {:f=>78, :g=>67}], :h=>4}}} 

我发现这个post,但我的情况是嵌套的哈希,所以任何帮助一些好的红宝石手将不胜感激。

基本上,我想“合并”相同命名键的数组值时对应于这些键的值是阵列。当然,下面将“与hash_2小号:stuff1阵列的:stuff1阵列(以及类似的:stuff2),但我想'的阵列+”式合并的替代hash_1,不是更新/更换,或合并! ...

hash_1.merge(hash_2) # NOT what I want => {:a=>{:b=>3, :c=>{:stuff1=>[{:d=>8, :e=>5}, {:d=>7, :e=>5}], :stuff2=>[{:f=>45, :g=>89}, {:f=>78, :g=>67}], :h=>4}}} 

我使用红宝石1.9.2,顺便说一句。我知道哈希已经稍微更新了一些,但我认为这不会影响答案。

谢谢!

+0

如果'hash_1 = {:a => {:b => 3 ..'和'hash_1 = {: A => {A:b => 4'? – tokland 2012-01-11 23:17:01

回答

1
# adapted from http://snippets.dzone.com/posts/show/4706 
class Hash 
    def deep_merge_with_array_values_concatenated(hash) 
    target = dup 

    hash.keys.each do |key| 
     if hash[key].is_a? Hash and self[key].is_a? Hash 
     target[key] = target[key].deep_merge_with_array_values_concatenated(hash[key]) 
     next 
     end 

     if hash[key].is_a?(Array) && target[key].is_a?(Array) 
     target[key] = target[key] + hash[key] 
     else 
     target[key] = hash[key] 
     end 
    end 

    target 
    end 
end 

p hash_1.deep_merge_with_array_values_concatenated(hash_2) 
1

您可以为合并方法定义块,将为每个复制密钥调用此块。

hash_1.merge(hash_2) do |key, old_value, new_value| 
    old_value + new_value 
end 
0

我认为规范是不完整的。无论如何,函数递归方法(第二个哈希仅用于连接数组值):

class Hash 
    def concat_on_common_array_values(hash) 
    Hash[map do |key, value| 
     if value.is_a?(Hash) && hash[key].is_a?(Hash) 
     [key, value.concat_on_common_array_values(hash[key])] 
     elsif value.is_a?(Array) && hash[key].is_a?(Array) 
     [key, value + hash[key]] 
     else 
     [key, value] 
     end  
    end] 
    end 
end 

p hash_1.concat_on_common_array_values(hash_2) 
# {:a=>{:b=>3, :c=>{:stuff1=>[{:d=>1, :e=>2}, {:d=>4, :e=>2}, {:d=>8, :e=>5}, {:d=>7, :e=>5}], :stuff2=>[{:f=>33, :g=>44}, {:f=>55, :g=>66}, {:f=>45, :g=>89}, {:f=>78, :g=>67}], :h=>4}}}