Iterating trough hash

Hi!

This is my first ruby day. I started reading the ruby book two hours ago and
want to do something useful now :slight_smile:
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

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

路路路

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?

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 :slight_smile:
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-schroeder.de/

not sure if it's more elegant, but

   harp:~ > cat a.rb
   h = {"john" => 41, "mary" => 31, "fred" => 10}

   sorted = h.sort
   sorted.each do |this|
     greater_than = h.select{|*that| (that <=> this) > 0}

     greater_than.each do |that|
       p0, a0, p1, a1 = this + that
       puts "#{ p0 } shakes hands with #{ p1 }. Together they are #{ a0 + a1 } years old"
     end
   end

   harp:~ > ruby a.rb
   fred shakes hands with john. Together they are 51 years old
   fred shakes hands with mary. Together they are 41 years old
   john shakes hands with mary. Together they are 72 years old

is, i think, closer to what you want. note that with your code the order of
output is undefined : keys come out of a hash in an undefined order. load your
hash with hundred entries and run a few times to see what i mean...

kind regards.

-a

路路路

On Tue, 9 Nov 2004, Kevin [ISO-8859-15] B枚rgens wrote:

Hi!

This is my first ruby day. I started reading the ruby book two hours ago and
want to do something useful now :slight_smile:
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

--

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

===============================================================================

Hi!

This is my first ruby day. I started reading the ruby book two hours ago and
want to do something useful now :slight_smile:
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

路路路

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

TIA,
Kevin

Hi!

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

Kevin

It's for arrays, not hashes, but I have a #each_unique_pair method for arrays:

http://phrogz.net/RubyLibs/rdoc/classes/Array.html#M000066

Source code is:

         def each_unique_pair
                 self.each_with_index{ |a,i|
                         self[(i+1)..-1].each{ |b| yield a,b }
                 }
         end

With a little manipulation of the hash, you should be able to get it into a format that the above would work with.

路路路

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

I have a hash and I want to iterate trough all pairs of values. An example:

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

路路路

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

--
Brian Schr枚der
http://www.brian-schroeder.de/

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.angio.net/

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.

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.

cheers and welcome to ruby!

-a

路路路

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

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

--

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

===============================================================================

> 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

路路路

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:

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

consider the meaning of the h.sort and how ruby will do it by default.

   h.sort => array of key value pairs sorted first on name then on age

   h.sort.index => look for the natural ordering of an entry where the
                   ordering has been defined by ruby's Array#sort method

you are correct in what you said - but what does that __mean__? if you think
of what would cause an index to be less than the index of another entry you'll
see what i mean: a particular key/val pair will only have a lesser index in
the array produced by h.sort if either the name in the entry sorts first or
the names are the same and the age sorts first. as you pointed out the names
cannot be the same since the data is stored in a hash - so why include age in
the search for ordering index when it can never be a tie breaker? eg this
code would have the same effect

   if h.keys.sort.index(person1) < h.keys.sort.index(person2)

my concern was that the OP included the age in the ordering search thinking it
had some effect - it doesn't. in fact dermining the name's (or name/age pair)
index into an ordered list is exactly the same as simply comparing names isn't
it:

   harp:~ > cat a.rb
   h = {"john" => 41, "mary" => 31, "fred" => 10}

   puts '---'
   h.each_key do |person1|
     h.each_key do |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
     end
   end

   puts '---'
   h.each_key do |person1|
     h.each_key do |person2|

       if person1 < person2 # <--

         age=(h[person1]+h[person2]).to_s
         puts "#{person1} shakes hands with #{person2}. Together they are #{age} years old"
       end
     end
   end

   harp:~ > ruby a.rb

路路路

On Wed, 10 Nov 2004, Mark Hubbart wrote:

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

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

so - why do you think the OP included age in the search? what was the code
trying to say?

kind regards.

-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

===============================================================================

This is a really long one, so (being new to the language), I'd
appreciate feedback. Note here we don't print dups, and we also can
provide a custom definition of whether two people are equal...However
it doesn't use a hash quite as the OP requested :slight_smile:

module Enumerable
def each_permutation
   history = Hash.new()
   each do |item1|
     each do |item2|
         history[item1] = 1
         yield [item1,item2] unless (item1 === item2 || history.has_key?(item2))
     end
   end
end
end

class Person
   attr_reader :age
   attr_reader :name
   
   def initialize(name,age)
      @name=name;
      @age=age;
   end

   def ===(other)
      return ((@age==other.age())&&(@name==other.name()))
   end
  
   def to_s
      @name
   end

end

@persons = [
   Person.new('Timmy',5),
   Person.new('Jimmy',10),
   Person.new('Sally',40)
]

@persons.each_permutation do | p1, p2 |
puts "#{p1} shakes hands with #{p2}. Together they are
#{p1.age()+p2.age()} years old."
end

路路路

On Wed, 10 Nov 2004 05:23:39 +0900, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

On Wed, 10 Nov 2004, Mark Hubbart wrote:

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

consider the meaning of the h.sort and how ruby will do it by default.

   h.sort => array of key value pairs sorted first on name then on age

   h.sort.index => look for the natural ordering of an entry where the
                   ordering has been defined by ruby's Array#sort method

you are correct in what you said - but what does that __mean__? if you think
of what would cause an index to be less than the index of another entry you'll
see what i mean: a particular key/val pair will only have a lesser index in
the array produced by h.sort if either the name in the entry sorts first or
the names are the same and the age sorts first. as you pointed out the names
cannot be the same since the data is stored in a hash - so why include age in
the search for ordering index when it can never be a tie breaker? eg this
code would have the same effect

   if h.keys.sort.index(person1) < h.keys.sort.index(person2)

my concern was that the OP included the age in the ordering search thinking it
had some effect - it doesn't. in fact dermining the name's (or name/age pair)
index into an ordered list is exactly the same as simply comparing names isn't
it:

   harp:~ > cat a.rb
   h = {"john" => 41, "mary" => 31, "fred" => 10}

   puts '---'
   h.each_key do |person1|
     h.each_key do |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
     end
   end

   puts '---'
   h.each_key do |person1|
     h.each_key do |person2|

       if person1 < person2 # <--

         age=(h[person1]+h[person2]).to_s
         puts "#{person1} shakes hands with #{person2}. Together they are #{age} years old"
       end
     end
   end

   harp:~ > ruby a.rb
   ---
   john shakes hands with mary. Together they are 72 years old
   fred shakes hands with john. Together they are 51 years old
   fred shakes hands with mary. Together they are 41 years old
   ---
   john shakes hands with mary. Together they are 72 years old
   fred shakes hands with john. Together they are 51 years old
   fred shakes hands with mary. Together they are 41 years old

so - why do you think the OP included age in the search? what was the code
trying to say?

kind regards.

-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

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

consider the meaning of the h.sort and how ruby will do it by default.

   h.sort => array of key value pairs sorted first on name then on age

   h.sort.index => look for the natural ordering of an entry where the
                   ordering has been defined by ruby's Array#sort method

you are correct in what you said - but what does that __mean__?

<snip explanation>

you are, of course, correct -- I overlooked the big picture. I was
pointing out that [person,age] were the correct arguments for that
method, but you were pointing out that there was a more appropriate
method that could be used. Sorry for the needless contradiction :slight_smile:

so - why do you think the OP included age in the search? what was the code
trying to say?

Just a guess, but perhaps they didn't think to use the #keys method. I
didn't automatically think of it when I saw this code. But only the OP
can actually answer the question fully :slight_smile:

cheers,
Mark

路路路

On Wed, 10 Nov 2004 05:23:39 +0900, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

On Wed, 10 Nov 2004, Mark Hubbart wrote:

kind regards.

-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

Hmm, that's not a good bug there, so I'll pull the "history" thing out
(I was trying to be too clever)...

module Enumerable
def each_permutation
   each do |item1|
     each do |item2|
         yield [item1,item2] unless (item1 === item2)
     end
   end
end
end

路路路

On Tue, 9 Nov 2004 16:34:55 -0500, Michael DeHaan <michael.dehaan@gmail.com> wrote:

This is a really long one, so (being new to the language), I'd
appreciate feedback. Note here we don't print dups, and we also can
provide a custom definition of whether two people are equal...However
it doesn't use a hash quite as the OP requested :slight_smile:

module Enumerable
def each_permutation
   history = Hash.new()
   each do |item1|
     each do |item2|
         history[item1] = 1
         yield [item1,item2] unless (item1 === item2 || history.has_key?(item2))
     end
   end
end
end

class Person
   attr_reader :age
   attr_reader :name

   def initialize(name,age)
      @name=name;
      @age=age;
   end

   def ===(other)
      return ((@age==other.age())&&(@name==other.name()))
   end

   def to_s
      @name
   end

end

@persons = [
   Person.new('Timmy',5),
   Person.new('Jimmy',10),
   Person.new('Sally',40)
]

@persons.each_permutation do | p1, p2 |
puts "#{p1} shakes hands with #{p2}. Together they are
#{p1.age()+p2.age()} years old."
end

On Wed, 10 Nov 2004 05:23:39 +0900, ara.t.howard@noaa.gov > > > <ara.t.howard@noaa.gov> wrote:
> On Wed, 10 Nov 2004, Mark Hubbart wrote:
>
>
>
> >> 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].
>
> consider the meaning of the h.sort and how ruby will do it by default.
>
> h.sort => array of key value pairs sorted first on name then on age
>
> h.sort.index => look for the natural ordering of an entry where the
> ordering has been defined by ruby's Array#sort method
>
> you are correct in what you said - but what does that __mean__? if you think
> of what would cause an index to be less than the index of another entry you'll
> see what i mean: a particular key/val pair will only have a lesser index in
> the array produced by h.sort if either the name in the entry sorts first or
> the names are the same and the age sorts first. as you pointed out the names
> cannot be the same since the data is stored in a hash - so why include age in
> the search for ordering index when it can never be a tie breaker? eg this
> code would have the same effect
>
> if h.keys.sort.index(person1) < h.keys.sort.index(person2)
>
> my concern was that the OP included the age in the ordering search thinking it
> had some effect - it doesn't. in fact dermining the name's (or name/age pair)
> index into an ordered list is exactly the same as simply comparing names isn't
> it:
>
> harp:~ > cat a.rb
> h = {"john" => 41, "mary" => 31, "fred" => 10}
>
> puts '---'
> h.each_key do |person1|
> h.each_key do |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
> end
> end
>
> puts '---'
> h.each_key do |person1|
> h.each_key do |person2|
>
> if person1 < person2 # <--
>
> age=(h[person1]+h[person2]).to_s
> puts "#{person1} shakes hands with #{person2}. Together they are #{age} years old"
> end
> end
> end
>
> harp:~ > ruby a.rb
> ---
> john shakes hands with mary. Together they are 72 years old
> fred shakes hands with john. Together they are 51 years old
> fred shakes hands with mary. Together they are 41 years old
> ---
> john shakes hands with mary. Together they are 72 years old
> fred shakes hands with john. Together they are 51 years old
> fred shakes hands with mary. Together they are 41 years old
>
> so - why do you think the OP included age in the search? what was the code
> trying to say?
>
> kind regards.
>
>
>
> -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
> ===============================================================================
>
>

Hmm, that's not a good bug there, so I'll pull the "history" thing out
(I was trying to be too clever)...

module Enumerable
def each_permutation
   each do |item1|
     each do |item2|
         yield [item1,item2] unless (item1 === item2)
     end
   end
end
end

Hello Michael,

I think, that this is not each_permutation, but each_ordered_pair_of_elements_in_the_set_except_for_equal_elements.

each_permutation would be all shuffles of the original enumerable.

And it is not what the OP wanted, as he wanted all unordered pairs. So maybe

module Enumerable
def each_self_pair
   each do |item1|
     each do |item2|
         yield [item1,item2]
     end
   end
end
end

{'me' => 1, 'you' => 1, 'him' => 1}.each_self_pair do | ((p1, a1), (p2, a2) |
  next if p1 <= p2
  puts "#{p1} and #{p2} with age #{a1 + a2}"
end

would be more appropriate.

Regards,

Brian

路路路

On Wed, 10 Nov 2004 06:41:08 +0900 Michael DeHaan <michael.dehaan@gmail.com> wrote:

[snip]

--
Brian Schr枚der
http://www.brian-schroeder.de/

oops. I'll try to correct myself now...

The method I defined should be called each_combination_pair; they
weren't permutations at all.

So, I submit a revised method:

module Enumerable
  def combinations(min=0, max = nil)
    size = 0
    com = []
    each do |item1|
      size += 1
      com += com.map{|item2| item2.dup << item1 }
    end
    com.select{|n| (min..max||size) === n.size}
  end
end

Then:

h.combinations(2,2).each do |(person1, age1), (person2, age2)|
  puts "#{person1} shakes hands with #{person2}." +
    "Together they are #{age1+age2} years old."
end

I'm sure #combinations could be optimized to not bother generating
combinations of the wrong size, but it's already questionable whether
the method is short to justify replacing the original code, which is
probably more efficient :slight_smile:

cheers,
Mark

路路路

On Wed, 10 Nov 2004 06:51:50 +0900, Brian Schr枚der <ruby@brian-schroeder.de> wrote:

On Wed, 10 Nov 2004 06:41:08 +0900 > > > Michael DeHaan <michael.dehaan@gmail.com> wrote:

> Hmm, that's not a good bug there, so I'll pull the "history" thing out
> (I was trying to be too clever)...
>
> module Enumerable
> def each_permutation
> each do |item1|
> each do |item2|
> yield [item1,item2] unless (item1 === item2)
> end
> end
> end
> end
>
>

Hello Michael,

I think, that this is not each_permutation, but each_ordered_pair_of_elements_in_the_set_except_for_equal_elements.

each_permutation would be all shuffles of the original enumerable.

And it is not what the OP wanted, as he wanted all unordered pairs. So maybe

"each_ordered_pair_of_elements_in_the_set_except_for_equal_elements"

But that would just be overly silly... :slight_smile:

路路路

On Wed, 10 Nov 2004 08:08:49 +0900, Mark Hubbart <discordantus@gmail.com> wrote:

On Wed, 10 Nov 2004 06:51:50 +0900, Brian Schr枚der > > > <ruby@brian-schroeder.de> wrote:
> On Wed, 10 Nov 2004 06:41:08 +0900 > > > > > > Michael DeHaan <michael.dehaan@gmail.com> wrote:
>
> > Hmm, that's not a good bug there, so I'll pull the "history" thing out
> > (I was trying to be too clever)...
> >
> > module Enumerable
> > def each_permutation
> > each do |item1|
> > each do |item2|
> > yield [item1,item2] unless (item1 === item2)
> > end
> > end
> > end
> > end
> >
> >
>
> Hello Michael,
>
> I think, that this is not each_permutation, but each_ordered_pair_of_elements_in_the_set_except_for_equal_elements.
>
> each_permutation would be all shuffles of the original enumerable.
>
> And it is not what the OP wanted, as he wanted all unordered pairs. So maybe

oops. I'll try to correct myself now...

The method I defined should be called each_combination_pair; they
weren't permutations at all.

So, I submit a revised method:

module Enumerable
  def combinations(min=0, max = nil)
    size = 0
    com = []
    each do |item1|
      size += 1
      com += com.map{|item2| item2.dup << item1 }
    end
    com.select{|n| (min..max||size) === n.size}
  end
end

Then:

h.combinations(2,2).each do |(person1, age1), (person2, age2)|
  puts "#{person1} shakes hands with #{person2}." +
    "Together they are #{age1+age2} years old."
end

I'm sure #combinations could be optimized to not bother generating
combinations of the wrong size, but it's already questionable whether
the method is short to justify replacing the original code, which is
probably more efficient :slight_smile:

cheers,
Mark