简体   繁体   中英

Ruby: Merge Hash containing Arrays

I am trying to merge two Hashes.I got the code from here . As you can see I want to add one more hobby to my list. There are many hobbies. When h1 is formed ,only one hobby was available. When the second hobby arrived I wanted to merge it with the previous hash.

The structure of the Hashes are :

h1 = {"students"=>[{"name"=>"bobby", "hobbies"=>[{"outdoor"=>"cycling"}]}]}

h2 = {"students"=>[{"name"=>"bobby", "hobbies"=>[{"indoor"=>"reading"}]}]}

I ran this code:

res = h1.merge(h2) {|key,val1,val2| val1.merge val2}

The error I got was:

 undefined method `merge' for [{"name"=>"bobby", "hobbies"=>[{"outdoor"=>"cycling"}]}]:Array (NoMethodError)

So since array is involved, I don't know what to do. Any Help.

Required Output:

{"students"=>[{"name"=>"bobby", "hobbies"=>[{"outdoor"=>"cycling", "indoor"=>"reading"}]}]}

The built-in marge method cannot do what you want. You should write the original code to merge these structure like this.

def recursive_merge(h1, h2)
   case h1
   when Hash
      (h1.keys + h2.keys).each do |key|
         if h1.include?(key) && h2.include?(key) then
            recursive_merge(h1[key], h2[key])
         elsif h2.include?(key)
            h1[key] = h2[key]
         end
      end
   when Array
      for i in 0...([h1.count, h2.count].max)
         if i < h1.count && i < h2.count then
            recursive_merge(h1[i], h2[i])
         elsif i < h2.count then
            h1[i] = h2[i]
         end
      end
   end
end

recursive_merge(h1, h2)
puts h1

This method results the follwing output. Please note that this method overwrites h1 itself.

{"students"=>[{"name"=>"bobby", "hobbies"=>[{"outdoor"=>"cycling", "indoor"=>"reading"}]}]}

The answer on your question might be:

h1.merge(h2) { |k, v1, v2| 
  v1.map.with_index { |v1e, idx| 
    v1e['hobbies'].first.merge! v2[idx]['hobbies'].first
    v1e  
  }
  v1 
}

#⇒ {
#  "students" => [
#    [0] {
#      "hobbies" => [
#        [0] {
#           "indoor" => "reading",
#          "outdoor" => "cycling"
#        }
#      ],
#         "name" => "bobby"
#    }
#  ]
# }

But I would definitely redesign hobbies to be a hash, not an array of hashes, eliminating weird first calls:

v1e['hobbies'].merge! v2[idx]['hobbies']

Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM