在ruby哈希中合并相同的命名数组

时间:2012-01-11 20:30:01

标签: ruby arrays hash ruby-1.9 ruby-1.9.2

我想采用这样的两种形式的哈希:

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,但我的情况是嵌套哈希,所以任何一些好的红宝石手的帮助都会受到赞赏。

基本上,当与这些键对应的值为 arrays 时,我想“合并”相同命名键的数组值。当然,以下替换 hash_1的{​​{1}}数组与:stuff1的{​​{1}}数组(以及hash_2类似) ,但我想要一个数组':stuff1'类型的合并,而不是更新/替换,或合并! ...

:stuff2

我正在使用ruby 1.9.2,顺便说一句。我知道哈希最近有所更新,但我认为这不会影响答案。

谢谢!

3 个答案:

答案 0 :(得分:1)

您可以为merge方法定义块,将为每个复制键调用此块。

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

答案 1 :(得分: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)

答案 2 :(得分: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}}}