`EnumerableOperator#product *`

`factors`, &`block``EnumerableOperator#sum *`

`summands`, &`block`

The `product`

operator iterates over the Cartesian product of the factors,
each of which must be `Enumerable`

.

The `sum`

operator iterates over the concatenation of the summands, each of
which must be `Enumerable`

.

Both operators have aliases: `tuples`

for `product`

;
`concatenation`

and `cat`

for `sum`

.

Called with a block, the operators yield one element of the sequence at a time to the block.

With or without a block, the operators return an `Enumerable`

which
delegates to the original `Enumerables`

, but does not explicitly construct
the entire collection. Calling another `Enumerable`

method, such as
`select`

or `collect`

, on this return value is an efficient way of
chaining these operators with other methods. Simply call `entries`

to get
the whole collection. Also, because the operators return an `Enumerable`

,
they can be used with the `for`

syntax; see the examples.

`EnumerableOperator#diagonal *`

`factors`, &`block`

The `diagonal`

operator iterates over the diagonal of the Cartesian product
of the factors, each of which must be `Enumerable`

. In other words, the
n-th entry of the diagonal is an array of the n-th entries of each factor. The
resulting sequence terminates when any one factor terminates. Hence the
sequence has the same length as the shortest factor.

Called with a block, `diagonal`

yields one element of the sequence at a
time to the block.

With or without a block, `diagonal`

returns an `Enumerable`

object
which is *independent* of the original `Enumerables`

. As with
`product`

and `sum`

, this allows chaining with other iterators and
using the `for`

syntax. Unlike `product`

and `sum`

, however, the
entire collection is generated and stored in the object returned by
`diagonal`

.

Internally, `diagonal`

does not enumerate the sequences in parallel, but in
the order in which they are given. If the sequences have side-effects of
enumeration, this may result in different behavior than if the sequences were
truly enumerated in parallel (e.g., see matz's approach using threads in the
Ruby FAQ: http://www.rubycentral.com/faq/rubyfaq-5.html#ss5.5
).

include EnumerableOperator diagonal enum0, enum1, ...

or

EnumerableOperator.diagonal enum0, enum1, ...

and similarly for product and sum.

require 'enum/op' include EnumerableOperator # using the 'for ... in ... end' construct: for i, j in product 1..4, "bar".."baz" printf "%6s", i.to_s + j; puts if j == "baz" end puts # prints: # 1bar 1bas 1bat 1bau 1bav 1baw 1bax 1bay 1baz # 2bar 2bas 2bat 2bau 2bav 2baw 2bax 2bay 2baz # 3bar 3bas 3bat 3bau 3bav 3baw 3bax 3bay 3baz # directly passing a block: sum 1..5, 'a'..'c', 90..92 do |i| printf "%4s", i.to_s end puts "\n\n" # prints: # 1 2 3 4 5 a b c 90 91 92 for i, j, k in diagonal 1..4, 'a'..'d', ?a..?d printf "%4d. %s is 0x%x\n", i, j, k end puts # prints: # 1. a is 0x61 # 2. b is 0x62 # 3. c is 0x63 # 4. d is 0x64 # chaining with other iterators: names = %w{ Ludwig Rudolf Bertrand Willard } more_names = %w{ Jean-Paul Albert Martin Soren } puts sum(names, more_names).sort.join ', ' puts # prints: # Albert, Bertrand, Jean-Paul, Ludwig, Martin, Rudolf, Soren, Willard # note that chaining avoids constructing the intermediate collection: big_product = product 1..10, 1..10, 1..10 big_product.select { |x, y, z| x <= y and x**2 + y**2 == z**2 }.each { |x, y, z| printf "#{x}**2 + #{y}**2 == #{z}**2\n" } # prints: # 3**2 + 4**2 == 5**2 # 6**2 + 8**2 == 10**2

Enumerable tools 1.4

The current version of this software can be found at http://redshift.sourceforge.net/enum .

This software is distributed under the Ruby license. See http://www.ruby-lang.org.

Joel VanderWerf, vjoel@sourceforge.net