Mering an array of hashes

L

Luke Grimstrup

I have two arrays of hashes and I would like to merge them.

One array has the array of:
{:id, :name}

The other, an array of:
{:name, :eek:ther_attributes*}

I've been raking my brains for hours on this one. Is there anyone who
can suggest the best way to merge these two arrays so that I can get the
resulting array of:
{:id. :name, :eek:ther_attributes}

Thanks so much in advance.
 
J

Jesús Gabriel y Galán

I have two arrays of hashes and I would like to merge them.

One array has the array of:
{:id, :name}

The other, an array of:
{:name, :eek:ther_attributes*}

I've been raking my brains for hours on this one. Is there anyone who
can suggest the best way to merge these two arrays so that I can get the
resulting array of:
{:id. :name, :eek:ther_attributes}

Is this what you are after? Not sure if I understood your description
correctly (an example of input and expected output would help):

irb(main):007:0> require 'generator'
irb(main):007:0> a = [{:id => 1}, {:id => 2}]
irb(main):007:0> b = [{:name => "a"}, {:name => "b"}]
irb(main):007:0> s = SyncEnumerator.new a,b
irb(main):007:0> s.map{|a,b| a.merge(b)}

=> [{:name=>"a", :id=>1}, {:name=>"b", :id=>2}]

Hope this helps,

Jesus.
 
L

Luke Grimstrup

Close, but not quite.

Here's an example:
hash #1: [{:name=>"File1.rar",
:id=>"a3d80425a51a3a4cb2d7a3201439ef6cc3af5874"}, {:name=>"File2.avi",
:id=>"58a658047ccb7333eb812da02dca9d84c1db2b41"}, {:name=>"File3.avi",
:id=>"944f6a7c50a4a5cff0c28cb0f9158b16580b0310"}]

hash #2 [{:name=>"File2.avi", :eek:ther_attributes =>"(350 MiB) - 2.85%
downloading at 0.00 B/s (UL at 0.00 B/s), stalled [error
(tracker-warning) - Tracker hasn't responded yet. Retrying...]"},
{:name=>"File1.rar", :eek:ther_attributes=>" (26.6 MiB) - 100% seeding at
0.00 B/s [0.23]"}, {:name=>"File3.avi", :eek:ther_attributes=>"(35.5 MiB) -
0.86% downloading at 0.00 B/s (UL at 0.00 B/s), stalled"}]

Note that the hashes I want to merge aren't necessarily at the same
index.
 
B

benjohn

I have two arrays of hashes and I would like to merge them.
One array has the array of:
{:id, :name}

The other, an array of:
{:name, :eek:ther_attributes*}

I've been raking my brains for hours on this one. Is there anyone who
can suggest the best way to merge these two arrays so that I can get the
resulting array of:
{:id. :name, :eek:ther_attributes}

I'm very confused by your notation above. Sorry to sound picky, but would
you be able to make it more clear?

Cheers,
B
 
L

Luke Grimstrup

Sorry B, late at night here :p

array #1: [{:name=>"File1.rar",
:id=>"a3d80425a51a3a4cb2d7a3201439ef6cc3af5874"}, {:name=>"File2.avi",
:id=>"58a658047ccb7333eb812da02dca9d84c1db2b41"}, {:name=>"File3.avi",
:id=>"944f6a7c50a4a5cff0c28cb0f9158b16580b0310"}]

array #2 [{:name=>"File2.avi", :eek:ther_attributes =>"stuff"},
{:name=>"File1.rar", :eek:ther_attributes=>"stuff"}, {:name=>"File3.avi",
:eek:ther_attributes=>"stuff"}]

And I would like the resulting array to look like:
array #1: [{:eek:ther_attributes => "stuff", :name=>"File1.rar",
:id=>"a3d80425a51a3a4cb2d7a3201439ef6cc3af5874"}, {:name=>"File2.avi",
:id=>"58a658047ccb7333eb812da02dca9d84c1db2b41", :eek:ther_attributes =>
"stuff"}, {:name=>"File3.avi",
:id=>"944f6a7c50a4a5cff0c28cb0f9158b16580b0310", :eek:ther_attributes =>
"stuff"}]

But I just have no idea how to do it. I'm sure there's an easy ruby way
to do it somehow..
 
B

benjohn

Sorry B, late at night here :p
array #1: [{:name=>"File1.rar",
:id=>"a3d80425a51a3a4cb2d7a3201439ef6cc3af5874"}, {:name=>"File2.avi",
:id=>"58a658047ccb7333eb812da02dca9d84c1db2b41"}, {:name=>"File3.avi",
:id=>"944f6a7c50a4a5cff0c28cb0f9158b16580b0310"}]

array #2 [{:name=>"File2.avi", :eek:ther_attributes =>"stuff"},
{:name=>"File1.rar", :eek:ther_attributes=>"stuff"}, {:name=>"File3.avi",
:eek:ther_attributes=>"stuff"}]

And I would like the resulting array to look like:
array #1: [{:eek:ther_attributes => "stuff", :name=>"File1.rar",
:id=>"a3d80425a51a3a4cb2d7a3201439ef6cc3af5874"}, {:name=>"File2.avi",
:id=>"58a658047ccb7333eb812da02dca9d84c1db2b41", :eek:ther_attributes =>
"stuff"}, {:name=>"File3.avi",
:id=>"944f6a7c50a4a5cff0c28cb0f9158b16580b0310", :eek:ther_attributes =>
"stuff"}]

But I just have no idea how to do it. I'm sure there's an easy ruby way
to do it somehow..

Ah, okay, that's clear, but pretty weird data :)

id_rows = a.map {|r| r.values_at:)name, :id)}
other_att_rows = b.map {|r| r.values_at:)name, :eek:ther_attributes)}
name_to_attr_map = Hash[*other_att_rows.flatten]
output = id_rows.map {|r| Hash[:name, r[0], :id, r[1], :eek:ther_attributes,
name_to_attr_map[r[0]]]}

Will work, and can be readily improved (exercise for reader ;-) - it'll be
niceer without turning the data in to an array of rows as I do in first
two lines).
 
U

Uwe s Schirmer

I would do it like this:

a1 = [{:name=>"File1.rar",
:id=>"a3d80425a51a3a4cb2d7a3201439ef6cc3af5874"},
{:name=>"File2.avi",
:id=>"58a658047ccb7333eb812da02dca9d84c1db2b41"},
{:name=>"File3.avi",
:id=>"944f6a7c50a4a5cff0c28cb0f9158b16580b0310"}]
a2 = [{:name=>"File2.avi", :eek:ther_attributes =>"stuff"},
{:name=>"File1.rar", :eek:ther_attributes=>"stuff"},
{:name=>"File3.avi", :eek:ther_attributes=>"stuff"}]


a3 = Array.new
a1.each do |entry1|
a2.each do |entry2|
if entry1[:name].eql? entry2[:name]
a3.push(entry1.merge(entry2))
break
end
end
end
p a3
 
L

Luke Grimstrup

Ah, that does work too!

A friend of mine told me what I "should" be doing to get it working, but
left the exercise of the coding it up to me.

Here's the magic:
hash_b.each{|d| d.merge!(hash_a.select{|e| e[:name] == d[:name]}.first)}
 
L

Luke Grimstrup

Actually, complete code:
a1 = [{:name=>"File1.rar",
:id=>"a3d80425a51a3a4cb2d7a3201439ef6cc3af5874"}, {:name=>"File2.avi",
:id=>"58a658047ccb7333eb812da02dca9d84c1db2b41"}, {:name=>"File3.avi",
:id=>"944f6a7c50a4a5cff0c28cb0f9158b16580b0310"}]

a2 = [{:name=>"File2.avi", :eek:ther_attributes =>"(350 MiB) - 2.85%
downloading at 0.00 B/s (UL at 0.00 B/s), stalled [error
(tracker-warning) - Tracker hasn't responded yet. Retrying...]"},
{:name=>"File1.rar", :eek:ther_attributes=>" (26.6 MiB) - 100% seeding at
0.00 B/s [0.23]"}, {:name=>"File3.avi", :eek:ther_attributes=>"(35.5 MiB) -
0.86% downloading at 0.00 B/s (UL at 0.00 B/s), stalled"}]

a2.each{|d| d.merge!(a1.select{|e| e[:name] == d[:name]}.first)}

Luke said:
Ah, that does work too!

A friend of mine told me what I "should" be doing to get it working, but
left the exercise of the coding it up to me.

Here's the magic:
hash_b.each{|d| d.merge!(hash_a.select{|e| e[:name] == d[:name]}.first)}
 
B

benjohn

Actually, complete code:
a1 = [{:name=>"File1.rar",
:id=>"a3d80425a51a3a4cb2d7a3201439ef6cc3af5874"}, {:name=>"File2.avi",
:id=>"58a658047ccb7333eb812da02dca9d84c1db2b41"}, {:name=>"File3.avi",
:id=>"944f6a7c50a4a5cff0c28cb0f9158b16580b0310"}]

a2 = [{:name=>"File2.avi", :eek:ther_attributes =>"(350 MiB) - 2.85%
downloading at 0.00 B/s (UL at 0.00 B/s), stalled [error
(tracker-warning) - Tracker hasn't responded yet. Retrying...]"},
{:name=>"File1.rar", :eek:ther_attributes=>" (26.6 MiB) - 100% seeding at
0.00 B/s [0.23]"}, {:name=>"File3.avi", :eek:ther_attributes=>"(35.5 MiB) -
0.86% downloading at 0.00 B/s (UL at 0.00 B/s), stalled"}]

a2.each{|d| d.merge!(a1.select{|e| e[:name] == d[:name]}.first)}

Hey - that comes out really cleanly. Cool.
 
D

David A. Black

Hi --

Actually, complete code:
a1 = [{:name=>"File1.rar",
:id=>"a3d80425a51a3a4cb2d7a3201439ef6cc3af5874"}, {:name=>"File2.avi",
:id=>"58a658047ccb7333eb812da02dca9d84c1db2b41"}, {:name=>"File3.avi",
:id=>"944f6a7c50a4a5cff0c28cb0f9158b16580b0310"}]

a2 = [{:name=>"File2.avi", :eek:ther_attributes =>"(350 MiB) - 2.85%
downloading at 0.00 B/s (UL at 0.00 B/s), stalled [error
(tracker-warning) - Tracker hasn't responded yet. Retrying...]"},
{:name=>"File1.rar", :eek:ther_attributes=>" (26.6 MiB) - 100% seeding at
0.00 B/s [0.23]"}, {:name=>"File3.avi", :eek:ther_attributes=>"(35.5 MiB) -
0.86% downloading at 0.00 B/s (UL at 0.00 B/s), stalled"}]

a2.each{|d| d.merge!(a1.select{|e| e[:name] == d[:name]}.first)}

Luke said:
Ah, that does work too!

A friend of mine told me what I "should" be doing to get it working, but
left the exercise of the coding it up to me.

Here's the magic:
hash_b.each{|d| d.merge!(hash_a.select{|e| e[:name] == d[:name]}.first)}

You can use #find rather than #select plus #first.


David
 
J

Jesús Gabriel y Galán

Close, but not quite.

You already got other solutions, but here is another one:

irb(main):001:0> a = [{:id => 1, :name => "a"}, {:id => 2, :name => "b"}]
irb(main):002:0> b = [{:eek:ther => "other_b_data", :name => "b"},
{:eek:ther => "other_a_data", :name => "a"}]
irb(main):003:0> h = Hash.new {|h,k| h[k] = {}}
irb(main):013:0> (a + b).each {|data| h[data[:name]].merge!(data)}
irb(main):015:0> h.values
=> [{:eek:ther=>"other_a_data", :name=>"a", :id=>1},
{:eek:ther=>"other_b_data", :name=>"b", :id=>2}]

I haven't measured the time, but this might have better performance
than finding in the second array by
name every time, since here we are accessing a hash by that key.

Hope this helps,

Jesus.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,073
Latest member
DarinCeden

Latest Threads

Top