An idiomatic way to traverse all pairs in an enumerable?

I seem to end up doing the following quite a lot:

enum.each do |a|
enum.each do |b|
next if a >= b
# do_something with a and b
end
end

In general, I’m looking for an idiomatic way of traversing each
possible pair of a given enum’s contents (once). Is there a more
compact construct?

(I assume I could finally grasp the whole block-passing side of Ruby
and write my own Enumerable#each_mix, but maybe there’s something there
already. Note: Enumerable#each_pair doesn’t cut it, as it’s just for
neighbouring element pairs, while I need something for all possible
pairs.)

Thanks in advance for any help with the above!

– Shot

On Dec 15, 2007, at 6:03 PM, Shot (Piotr S.) wrote:

possible pair of a given enum’s contents (once). Is there a more

– Shot

The existential root of libertarianism is the experience of
being very bad at taking orders from morons. – Leopold Leider

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/42671

You could use the Array#combination code posted there either directly
or as an example. If you can rely on the ordering of elements (your
a>=b), your code isn’t too bad, but the code on the ruby list will be
(is) part of Ruby1.9 and only depends on position within the Array.
If you have an enumerable that’s not an Array, you might have some
tweaking to do anyway.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

On Dec 15, 6:25 pm, Rob B. [email protected]
wrote:

end
neighbouring element pairs, while I need something for all possible

[email protected]
module Enumerable
def every_pair(other)
self.each { | x |
other.each { | y |
yield [x, y] if x < y
}
}
end
end

a = [1, 8, 3]
b = [4, 5, 6]
a.every_pair(b) { | x, y |
puts "doing stuff with " + [x, y].inspect
}

=>

doing stuff with [1, 4]
doing stuff with [1, 5]
doing stuff with [1, 6]
doing stuff with [3, 4]
doing stuff with [3, 5]
doing stuff with [3, 6]

Regards,
Jordan

MonkeeSage:

module Enumerable
def every_pair(other)
self.each { | x |
other.each { | y |
yield [x, y] if x < y
}
}
end
end

Ah, perfect. In my (limited) case, it ended up to be

module Enumerable
def every_pair
each_with_index do |a, i|
each_with_index do |b, j|
yield [a, b] if i < j
end
end
end
end

arr = (1…5).sort_by { rand }
=> [1, 4, 2, 5, 3]

arr.every_pair { |a, b| p [a, b] }
[1, 4]
[1, 2]
[1, 5]
[1, 3]
[4, 2]
[4, 5]
[4, 3]
[2, 5]
[2, 3]
[5, 3]
=> [1, 4, 2, 5, 3]

Most appreciated!

– Shot

On Dec 15, 6:03 pm, “Shot (Piotr S.)” [email protected] wrote:

possible pair of a given enum’s contents (once). Is there a more
compact construct?

Facets exits for you.

http://facets.rubyforge.org/rdoc/core/classes/Enumerable.html#M000450

T.

http://facets.rubyforge.org

Trans:

On Dec 15, 6:03 pm, “Shot (Piotr S.)” [email protected] wrote:

In general, I’m looking for an idiomatic way of traversing
each possible pair of a given enum’s contents (once).

Facets exits for you.

(I can’t help but love the typo.)

http://facets.rubyforge.org/rdoc/core/classes/Enumerable.html#M000450

Ah, thanks – I have both Facets’ and Utility Belt’s documentation
on my to-read list, but didn’t have the time yet. :slight_smile:

– Shot

Rob B.:

On Dec 15, 2007, at 6:03 PM, Shot (Piotr S.) wrote:

In general, I’m looking for an idiomatic way of traversing
each possible pair of a given enum’s contents (once).

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-list/42671

You could use the Array#combination code
posted there either directly or as an example.

Thanks a lot!

In a related field, the above touched some obscure part of my brain
and I recalled the permutation gem: http://permutation.rubyforge.org/

If you can rely on the ordering of elements
(your a>=b), your code isn’t too bad

If I can’t rely on it, I use each_with_index:

each_with_index do |a, i|
each_with_index do |b, j|
next if i >= j
# do something with a and b
end
end

If you have an enumerable that’s not an Array,
you might have some tweaking to do anyway.

The above each_with_index works quite well for most
(all?) enumerables. :slight_smile: Thanks again for your reply!

– Shot