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!
on 2012-11-06 14:06
on 2012-11-06 14:25
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
#-------------------------------------
on 2012-11-06 14:33
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
on 2012-11-06 14:59
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.
on 2012-11-06 15:09
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).
on 2012-11-06 16:55
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?
on 2012-11-06 17:14
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
#-------------------------
on 2012-11-06 17:29
> 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 2012-11-06 23:38
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! > 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 2012-11-07 09:42
> I'd rather use Set here since apparently entries must be present only > once: > > require 'set' Interesting, didn't knew about 'set'. Thanks.
on 2012-11-07 10:26
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 2012-11-07 10:34
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.
on 2012-11-07 15:04
On Wed, Nov 7, 2012 at 10:34 AM, Jermaine O. <lists@ruby-forum.com> 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
on 2012-11-07 15:08
> Sorry, what did you mean? Are you still stuck or were you stuck? > > Kind regards > > robert No :) I meant that I sticked with the approach of using the block form of Hash#merge
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.