Reputation: 103
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
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
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