How to merge two or more hashes in to one?

Hi everyone.

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

foo = {"luxuy" => ["Mercedes", "BMW"], "sport" => ["porsche","ferrari"]}
bar = {"luxuy" => ["BMW", "Bentley", "Rolls Royce"],
"sport"=>["lamborghini"]}

Then this is the result I'm looking for when merging the two:
result = {"luxuy" => ["Mercedes", "BMW", "Bentley", "Rolls
Royce"],"sport" => ["porsche", "ferrari", "lamborghini"]}

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

Thanks!

···

--
Posted via http://www.ruby-forum.com/.

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
end
p merg
#-------------------------------------

--
Posted via http://www.ruby-forum.com/.

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

···

--
Posted via http://www.ruby-forum.com/.

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.

···

--
Posted via http://www.ruby-forum.com/.

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.

···

--
Posted via http://www.ruby-forum.com/\.

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.

···

--
Posted via http://www.ruby-forum.com/\.

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).

···

--
Posted via http://www.ruby-forum.com/\.

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.

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

···

On Wed, Nov 7, 2012 at 10:34 AM, Jermaine O. <lists@ruby-forum.com> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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?

···

--
Posted via http://www.ruby-forum.com/\.

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

···

--
Posted via http://www.ruby-forum.com/\.

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

--
Posted via http://www.ruby-forum.com/\.

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!

···

--
Posted via http://www.ruby-forum.com/\.

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

···

On Tue, Nov 6, 2012 at 5:29 PM, Jermaine O. <lists@ruby-forum.com> 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!

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

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

require 'set'

Interesting, didn't knew about 'set'. Thanks.

···

--
Posted via http://www.ruby-forum.com/\.