[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Iterating trough hash

Kevin Börgens

11/9/2004 4:06:00 PM

Hi!

This is my first ruby day. I started reading the ruby book two hours ago and
want to do something useful now :-)
I have a hash and I want to iterate trough all pairs of values. An example:

h = {"john" => 41, "mary" => 31, "fred" => 10}
#insert control structure here
age=(h[person1]+h[person2]).to_s
puts "#person1 shakes hands with #person2. Together they are #age
years old"


The output could for example be:

john shakes hands with mary. Together they are 72 years old
john shakes hands with fred. Together they are 51 years old
mary shakes hands with fred. Together they are 41 years old


what I do at the moment:

h = {"john" => 41, "mary" => 31, "fred" => 10}
h.each_key{|person1|
h.each_key{|person2|
if h.sort.index([person1,h[person1]])<h.sort.index([person2,h[person2]])
age=(h[person1]+h[person2]).to_s
puts "#{person1} shakes hands with #{person2}. Together they are
#{age} years old"
end }}

Is there a more elegant way to do this?

TIA,
Kevin
18 Answers

James Gray

11/9/2004 4:17:00 PM

0

On Nov 9, 2004, at 10:08 AM, Kevin Börgens wrote:

> h = {"john" => 41, "mary" => 31, "fred" => 10}
> h.each_key{|person1|
> h.each_key{|person2|
> if
> h.sort.index([person1,h[person1]])<h.sort.index([person2,h[person2]])
> age=(h[person1]+h[person2]).to_s
> puts "#{person1} shakes hands with #{person2}. Together they are
> #{age} years old"
> end }}
>
> Is there a more elegant way to do this?

Well, we can simplify that a bit. How about:

#!/usr/bin/env ruby

h = {"john" => 41, "mary" => 31, "fred" => 10}
h.each_key do |person1|
h.each_key do |person2|
puts "#{person1} shakes hands with #{person2}. " +
"Together they are #{h[person1] + h[person2]} years old."
end
end

__END__

I'm not very clear on what you were aiming for with the if statement,
but if you tell me, I can probably add that back a little slimmer too.

Hope that helps.

James Edward Gray II




Brian Schröder

11/9/2004 4:22:00 PM

0

Hello Kevin,

as the hash key is unique it should suffice to do it like this.

h = {"john" => 41, "mary" => 31, "fred" => 10}
h.each do | person1, age1 |
h.each do | person2, age2 |
next if person1 <= person2
puts "#{person1} shakes hands with #{person2}. Together they are #{age1 + age2} years old"
end
end

Note that you made an error with the string interpolation. I assume you are coming from php where you only need the $, here in ruby we need the braces.

Regards,

Brian


On Wed, 10 Nov 2004 01:08:38 +0900
Kevin Börgens <kevin@boergens.de> wrote:

> Hi!
>
> This is my first ruby day. I started reading the ruby book two hours ago and
> want to do something useful now :-)
> I have a hash and I want to iterate trough all pairs of values. An example:
>
> h = {"john" => 41, "mary" => 31, "fred" => 10}
> #insert control structure here
> age=(h[person1]+h[person2]).to_s
> puts "#person1 shakes hands with #person2. Together they are #age
> years old"
>
>
> The output could for example be:
>
> john shakes hands with mary. Together they are 72 years old
> john shakes hands with fred. Together they are 51 years old
> mary shakes hands with fred. Together they are 41 years old
>
>
> what I do at the moment:
>
> h = {"john" => 41, "mary" => 31, "fred" => 10}
> h.each_key{|person1|
> h.each_key{|person2|
> if h.sort.index([person1,h[person1]])<h.sort.index([person2,h[person2]])
> age=(h[person1]+h[person2]).to_s
> puts "#{person1} shakes hands with #{person2}. Together they are
> #{age} years old"
> end }}
>
> Is there a more elegant way to do this?
>
> TIA,
> Kevin
>


--
Brian Schröder
http://www.brian-sch...



Brian Schröder

11/9/2004 4:24:00 PM

0

On Wed, 10 Nov 2004 01:17:27 +0900
James Edward Gray II <james@grayproductions.net> wrote:

> On Nov 9, 2004, at 10:08 AM, Kevin Börgens wrote:
>
> > h = {"john" => 41, "mary" => 31, "fred" => 10}
> > h.each_key{|person1|
> > h.each_key{|person2|
> > if
> > h.sort.index([person1,h[person1]])<h.sort.index([person2,h[person2]])
> > age=(h[person1]+h[person2]).to_s
> > puts "#{person1} shakes hands with #{person2}. Together they are
> > #{age} years old"
> > end }}
> >
> > Is there a more elegant way to do this?
>
> Well, we can simplify that a bit. How about:
>
> #!/usr/bin/env ruby
>
> h = {"john" => 41, "mary" => 31, "fred" => 10}
> h.each_key do |person1|
> h.each_key do |person2|
> puts "#{person1} shakes hands with #{person2}. " +
> "Together they are #{h[person1] + h[person2]} years old."
> end
> end
>
> __END__
>
> I'm not very clear on what you were aiming for with the if statement,
> but if you tell me, I can probably add that back a little slimmer too.
>
> Hope that helps.
>
> James Edward Gray II
>
>

I think he did not want ordered pairs, and only pairs with unequal members.

On a site note, I think there should be a performance penalty, in looking up the values in the hash after getting the key. I'd imagine that .each do | person, age | would be faster.

Regards,

Brian

--
Brian Schröder
http://www.brian-sch...



David G. Andersen

11/9/2004 4:26:00 PM

0

On Wed, Nov 10, 2004 at 01:17:27AM +0900, James Edward Gray II scribed:
> > if
> >h.sort.index([person1,h[person1]])<h.sort.index([person2,h[person2]])
> > age=(h[person1]+h[person2]).to_s
> > puts "#{person1} shakes hands with #{person2}. Together they are
> >#{age} years old"
> > end }}
> >
> >Is there a more elegant way to do this?
>
> Well, we can simplify that a bit. How about:
>
> #!/usr/bin/env ruby
>
> h = {"john" => 41, "mary" => 31, "fred" => 10}
> h.each_key do |person1|
> h.each_key do |person2|
> puts "#{person1} shakes hands with #{person2}. " +
> "Together they are #{h[person1] + h[person2]} years
> old."
> end
> end
>
> __END__
>
> I'm not very clear on what you were aiming for with the if statement,
> but if you tell me, I can probably add that back a little slimmer too.

Canonicalizing the order and making sure that john doesn't
shake hands with himself, as he would in the above revision.
This is one case where the "for loop" solution is probably
more elegant:

h = {"john" => 41, "mary" => 31, "fred" => 10}
people = h.keys
(0..people.length).each do |p1|
(p1+1...people.length).each do |p2|
puts "..."
end
end

(note the '...' in the second for loop)

-dave

--
work: dga@lcs.mit.edu me: dga@pobox.com
MIT Laboratory for Computer Science http://www....


Kevin Börgens

11/9/2004 4:38:00 PM

0

Hi!
> #!/usr/bin/env ruby
>
> h = {"john" => 41, "mary" => 31, "fred" => 10}
> h.each_key do |person1|
> h.each_key do |person2|
> puts "#{person1} shakes hands with #{person2}. " +
> "Together they are #{h[person1] + h[person2]} years old."
> end
> end
No, this programm would iterate like this
john john
john mary
john fred
mary john
mary mary
mary fred
fred john
fred mary
fred fred

> I'm not very clear on what you were aiming for with the if statement,
> but if you tell me, I can probably add that back a little slimmer too.
Therefore I used the example with shaking hands. You don't shake hands with
yourself and it doesn't matter who is person1 or person2

TIA,
Kevin

Ara.T.Howard

11/9/2004 4:41:00 PM

0

Ara.T.Howard

11/9/2004 4:58:00 PM

0

Mark Hubbart

11/9/2004 6:19:00 PM

0

On Wed, 10 Nov 2004 01:08:38 +0900, Kevin Börgens <kevin@boergens.de> wrote:
> Hi!
>
> This is my first ruby day. I started reading the ruby book two hours ago and
> want to do something useful now :-)
> I have a hash and I want to iterate trough all pairs of values. An example:
>
> h = {"john" => 41, "mary" => 31, "fred" => 10}
> #insert control structure here
> age=(h[person1]+h[person2]).to_s
> puts "#person1 shakes hands with #person2. Together they are #age
> years old"
>
> The output could for example be:
>
> john shakes hands with mary. Together they are 72 years old
> john shakes hands with fred. Together they are 51 years old
> mary shakes hands with fred. Together they are 41 years old
>
> what I do at the moment:
>
> h = {"john" => 41, "mary" => 31, "fred" => 10}
> h.each_key{|person1|
> h.each_key{|person2|
> if h.sort.index([person1,h[person1]])<h.sort.index([person2,h[person2]])
> age=(h[person1]+h[person2]).to_s
> puts "#{person1} shakes hands with #{person2}. Together they are
> #{age} years old"
> end }}
>
> Is there a more elegant way to do this?

Myself, I would add a method to Enumerable. This lets you separate a
lot of the logic:

module Enumerable
def each_permutation
history = []
each do |item1|
history.each{|item2| yield [item1,item2]}
history << item1
end
end
end

Then:

h = {"john" => 41, "mary" => 31, "fred" => 10}
h.each_permutation do |(person1, age1), (person2, age2)|
puts "#{person1} shakes hands with #{person2}." +
"Together they are #{age1+age2} years old."
end

HTH,
Mark

> TIA,
> Kevin
>
>



Mark Hubbart

11/9/2004 6:29:00 PM

0

On Wed, 10 Nov 2004 02:03:45 +0900, ara.t.howard@noaa.gov
<ara.t.howard@noaa.gov> wrote:
>
>
> On Tue, 9 Nov 2004, Kevin [ISO-8859-15] Börgens wrote:
>
> > Hi!
> >> #!/usr/bin/env ruby
> >>
> >> h = {"john" => 41, "mary" => 31, "fred" => 10}
> >> h.each_key do |person1|
> >> h.each_key do |person2|
> >> puts "#{person1} shakes hands with #{person2}. " +
> >> "Together they are #{h[person1] + h[person2]} years old."
> >> end
> >> end
> > No, this programm would iterate like this
> > john john
> > john mary
> > john fred
> > mary john
> > mary mary
> > mary fred
> > fred john
> > fred mary
> > fred fred
> >
> >> I'm not very clear on what you were aiming for with the if statement,
> >> but if you tell me, I can probably add that back a little slimmer too.
> > Therefore I used the example with shaking hands. You don't shake hands with
> > yourself and it doesn't matter who is person1 or person2
> >
> > TIA,
> > Kevin
>
> that makes sense - but why, in your code, are you checking that the person's
> name AND/OR age are less than the other person? eg this line
>
> if h.sort.index([person1,h[person1]]) < h.sort.index([person2,h[person2]])
>
> says:
>
> if the name of person1 is less than the name of person2 OR the names are the
> SAME but the age of person1 is less than the age of person2.

Um, no, I think this says:

if the index of the first element that matches [person1, age1] is
greater than the
index of the first element that matches [person2, age2].

>
> example:
>
> harp:~ > irb
>
> irb(main):001:0> list = ['john', 42], ['john', 41]
> => [["john", 42], ["john", 41]]
>
> irb(main):002:0> a, b = list.first, list.last
> => [["john", 42], ["john", 41]]
>
> irb(main):003:0> list.index(a)
> => 0
>
> irb(main):004:0> list.index(b)
> => 1
>
> irb(main):005:0> list.index(a) < list.index(b)
> => true
>
> and john is shaking hands with john. ruby sorts array by using this algorithim:
>
> compare the first elements, if tied
> compare the second elements, if tied
> compare the third elelments, etc....
> etc....
>
> so the comparison you are making by checking the sort order (index position of
> entry) checks both name AND age - which may or may not be what you want.

But, since this array starts out its life as a hash, there will never
be duplicate names. So the ages will never be compared.

cheers,
Mark

>
> cheers and welcome to ruby!
>
>
>
> -a
> --
> ===============================================================================
> | EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
> | PHONE :: 303.497.6469
> | When you do something, you should burn yourself completely, like a good
> | bonfire, leaving no trace of yourself. --Shunryu Suzuki
> ===============================================================================
>
>



Kevin Börgens

11/9/2004 7:54:00 PM

0

Hi!

I'd like to thank everybody who helped me. You enhanced my knowledge about
Ruby.

Kevin