2012-01-11 2 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_1 «s :stuff1 массива с hash_2„s :stuff1 массива (и аналогично для :stuff2), но я хочу, массив“+» типа слияния, а не обновление/заменить или объединить! ...

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}}} 

Я использую ruby ​​1.9.2, кстати. Я знаю, что хеши обновлены немного в последнее время, хотя я не думаю, что это повлияет на ответ.

Спасибо!

+0

что, если 'hash_1 = {: а => {: Ь => 3 ..' и' hash_1 = {: а => {: Ь => 4'? – tokland

ответ

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

Я думаю, что технические характеристики не являются полными. Во всяком случае, функциональный подход рекурсивным (второй хэш используется только для Concat значения на значения массива):

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}}} 
Смежные вопросы