Iterating trough hash

K

Kevin Börgens

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
 
J

James Edward Gray II

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
 
B

Brian Schröder

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


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
 
B

Brian Schröder

On said:
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
 
D

David G. Andersen

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
 
K

Kevin Börgens

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
 
A

Ara.T.Howard

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

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
--
===============================================================================
| 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
===============================================================================
 
A

Ara.T.Howard

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 arethe
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 positionof
entry) checks both name AND age - which may or may not be what you want.

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
===============================================================================
 
M

Mark Hubbart

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
 
M

Mark Hubbart

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
===============================================================================
 
K

Kevin Börgens

Hi!

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

Kevin
 
A

Ara.T.Howard

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
===============================================================================
 
M

Michael DeHaan

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

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




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
===============================================================================
 
M

Michael DeHaan

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




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

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

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
===============================================================================
 
B

Brian Schröder

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
 
M

Mark Hubbart

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

cheers,
Mark
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
===============================================================================
 
M

Mark Hubbart

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

cheers,
Mark
 
M

Michael DeHaan

"each_ordered_pair_of_elements_in_the_set_except_for_equal_elements"

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


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

cheers,
Mark
 

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,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top