How to merge two or more hashes in to one?

Hi everyone.

I would like to merge two (or more) hashes into one single hash.
Imagine I have the following two hashes:

foo = {“luxuy” => [“Mercedes”, “BMW”], “sport” => [“Ferrari”]}
bar = {“luxuy” => [“BMW”, “Bentley”], “sport”=>[“Lamborghini”]}

Then this is the result I’m looking for when merging the two:

{
“luxuy” => [“Mercedes”, “BMW”, “Bentley”],
“sport” => [“Ferrari”,“Lamborghini”]
}

Any thoughts of how to easily achieve this? I’ve messed around with
.merge but without any success.

Thanks!

Hi,

this is a very special form of “merging”, so I don’t think there’s a
built-in method for this.

But you can use the block form of Hash#merge:

#-------------------------------------
foo = {“luxuy” => [“Mercedes”, “BMW”], “sport” => [“Ferrari”]}
bar = {“luxuy” => [“BMW”, “Bentley”], “sport”=>[“Lamborghini”]}

merg = foo.merge bar do |_, arr_1, arr_2|
arr_1 | arr_2 # array union
end
p merg
#-------------------------------------

Off the top of my head I’d just do this:

foo.each do |one,two|
foo[one] << bar[one]
foo[one].flatten!
foo[one].uniq!
end

Jan E. wrote in post #1083135:

Hi,

this is a very special form of “merging”, so I don’t think there’s a
built-in method for this.

But you can use the block form of Hash#merge:

#-------------------------------------
foo = {“luxuy” => [“Mercedes”, “BMW”], “sport” => [“Ferrari”]}
bar = {“luxuy” => [“BMW”, “Bentley”], “sport”=>[“Lamborghini”]}

merg = foo.merge bar do |_, arr_1, arr_2|
arr_1 | arr_2 # array union
end
p merg
#-------------------------------------

Thanks, that worked out, but I’m wondering how this applies when I have
more than 2 hashes. Because then this wouldn’t work.

Jermaine O. wrote in post #1083143:

Thanks, that worked out, but I’m wondering how this applies when I have
more than 2 hashes. Because then this wouldn’t work.

So what? Simply merge the hashes one by one (in a loop, with
Enumerable#inject or whatever).

Jan E. wrote in post #1083144:

Jermaine O. wrote in post #1083143:

Thanks, that worked out, but I’m wondering how this applies when I have
more than 2 hashes. Because then this wouldn’t work.

So what? Simply merge the hashes one by one (in a loop, with
Enumerable#inject or whatever).

Hi Jan, I appreciate your help but care to give an example?

The same thing can be achieved with Enumerable#inject, which is the
generalization of this kind of “sum up the elements of a collection”:

Just what I need. Many thanks for this, works great. Appreciate it!

On Tue, Nov 6, 2012 at 5:29 PM, Jermaine O. [email protected]
wrote:

The same thing can be achieved with Enumerable#inject, which is the
generalization of this kind of “sum up the elements of a collection”:

Just what I need. Many thanks for this, works great. Appreciate it!

I’d rather use Set here since apparently entries must be present only
once:

require ‘set’

merged = Hash.new {|h,k| h[k] = Set.new}

hashes.each do |hash|
hash.each {|k, v| merged[k].merge(v)}
end

Cheers

robert

Jermaine O. wrote in post #1083159:

Hi Jan, I appreciate your help but care to give an example?

I suppose you have an array of hashes. Define a variable for the
intermediate results and initialize it with an empty hash. Then you loop
through the hashes and merge each one with the intermediate hash:

#-------------------------
data = [
{luxury: [“Mercedes”, “BMW”], sport: [“Ferrari”]},
{luxury: [“BMW”, “Bentley”], sport: [“Lamborghini”]},
{luxury: [“something luxury”], sport: [“something sporty”]},
]

merged = {}
data.each do |cars|
merged.merge!(cars) {|_, v_1, v_2| v_1 | v_2}
end
p merged
#-------------------------

The same thing can be achieved with Enumerable#inject, which is the
generalization of this kind of “sum up the elements of a collection”:

#-------------------------
merged = data.inject do |cars_1, cars_2|
cars_1.merge(cars_2) {|_, v_1, v_2| v_1 | v_2}
end
p merged
#-------------------------

I’d rather use Set here since apparently entries must be present only
once:

require ‘set’

Interesting, didn’t knew about ‘set’. Thanks.

Well, in this case I don’t really see the advantage of using sets. The
only difference it makes is that arr_1 | arr_2 becomes
set_1.merge(set_2).

So unless you plan to actually use the special features of sets, I’d
stick with standard arrays.

But I don’t want this to turn into yet another endless discussion about
implementation details, so do whatever you think fits best.

On Wed, Nov 7, 2012 at 10:34 AM, Jermaine O. [email protected]
wrote:

Yeah. I just tend to use Set in situations where the content is
supposed
to be unique - if not for efficiency reasons then for documentation.

Got the work done and stuck with the merge block approach.

Sorry, what did you mean? Are you still stuck or were you stuck?

Kind regards

robert

Sorry, what did you mean? Are you still stuck or were you stuck?

Kind regards

robert

No :slight_smile: I meant that I sticked with the approach of using the block form
of Hash#merge

Jan E. wrote in post #1083271:

Well, in this case I don’t really see the advantage of using sets. The
only difference it makes is that arr_1 | arr_2 becomes
set_1.merge(set_2).

So unless you plan to actually use the special features of sets, I’d
stick with standard arrays.

But I don’t want this to turn into yet another endless discussion about
implementation details, so do whatever you think fits best.

Got the work done and stuck with the merge block approach.