mia102aim
mia102aim

Reputation: 103

Merging hashes into arrays

I'm new in Ruby. I have two arrays of hashes

arr1 = [{"one"=> {"1"=> "a", "2" => "b"}, "two" => {"3" => "n", "5" => "h", "7" => "k"}]
arr2 = [{"one"=> {"8"=> "f", "11" => "r"}, "two" => {"7" => "o", "6" => "b", "14" => "b"}]

and I want to have one array like this:

arr3 = [{
"one"=> {"1"=> "a", "2" => "b", "8"=> "f", "11" => "r"}, 
"two" => {3" => 'n", "5" => "h", "7" => "k", 7" => 'o", "6" => "b", "14" => "b"}
]

so I want to merge hashes by keys and "add" their values. Can anyone help?

Upvotes: 0

Views: 73

Answers (2)

stevensonmt
stevensonmt

Reputation: 732

Maybe not the most elegant but this works:

arr1 = [{"one"=>{"1"=>"a",  "2"=>"b"}, "two"=>{"3"=>"n", "5"=>"h",  "7"=>"k"}}]
arr2 = [{"one"=>{"8"=>"f", "11"=>"r"}, "two"=>{"7"=>"o", "6"=>"b", "14"=>"b"}}]
arr3 = []
arr1[0].each_key{|k| arr3<< {k => arr1[0][k].merge(arr2[0][k])}}
arr3

If you don't know how many hashes your original array will contain, simply replace arr1[0].each_key with arr1.each_index{|i| arr1[i].each_key and replace 0 with i in the merge.

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110675

arr1 = [{"one"=>{"1"=>"a",  "2"=>"b"}, "two"=>{"3"=>"n", "5"=>"h",  "7"=>"k"}}]
arr2 = [{"one"=>{"8"=>"f", "11"=>"r"}, "two"=>{"7"=>"o", "6"=>"b", "14"=>"b"}}]

(arr1+arr2).each_with_object({}) { |g,h| h.update(g) { |_,o,n| o.merge(n) } }
  # => {"one"=>{"1"=>"a", "2"=>"b", "8"=>"f", "11"=>"r"},
  #     "two"=>{"3"=>"n", "5"=>"h", "7"=>"o", "6"=>"b", "14"=>"b"}}

This uses the form of Hash#update (aka merge!) that uses a block ({ |_k,o,n| o.merge(n) }) to determine the value of the key _k when both hashes being merged have that key. (_ in _k tells the reader that that block variable is not used in the block calculation.) o and n are the values of that key in h and g respectively.

For each key k equal to "one" or "two", if the values (hashes) of arr1.first[k] and arr2.first[k] have a common key l, the merge operation will cause the value of l in arr1 will be overwritten by the value of l in arr2. If, for example, arr1.first["one"] #=> {"1"=>"a", "2"=>"b"} and arr2.first["one"] #=> {"8"=>"f", "2"=>"r"}, the merge will return {"1"=>"a", "2"=>"r", "8"=>"f"}

Even though arr1 and arr2 each contain a single element (a hash), the code above works fine when the arrays contain multiple hashes, and when there are more than two arrays. If the arrays always contain a single hash, the arrays serve no purpose and we might instead just reference the hashes:

h1 = {"one"=>{"1"=>"a",  "2"=>"b"}, "two"=>{"3"=>"n", "5"=>"h",  "7"=>"k"}}
h2 = {"one"=>{"8"=>"f", "11"=>"r"}, "two"=>{"7"=>"o", "6"=>"b", "14"=>"b"}}

and replace arr1+arr2 with [h1+h2].

Upvotes: 1

Related Questions