Project

General

Profile

Actions

Feature #18685

closed

Enumerator.product: Cartesian product of enumerables

Added by knu (Akinori MUSHA) about 2 years ago. Updated over 1 year ago.

Status:
Closed
Assignee:
-
Target version:
[ruby-core:108198]

Description

I'd like to add a new Enumerator class method for generating the Cartesian product of given enumerators.
A product here does not mean an accumulated array of arrays, but an enumerator to enumerate all combinations.

product = Enumerator.product(1..3, ["A", "B"])
p product.class #=> Enumerator

product.each do |i, c|
  puts "#{i}-#{c}"
end

=begin output
1-A
1-B
2-A
2-B
3-A
3-B
=end

This can be used to reduce nested blocks and allows for iterating over an indefinite number of enumerable objects.

Implementation notes

  • It should internally use each_entry instead of each on enumerable objects to make sure to capture all yielded arguments.

  • If no enumerable object is given, the block is called once with no argument.

  • It should reject a keyword-style hash argument so we can add keyword arguments in the future without breaking existing code.

  • Here's an example implementation:

    # call-seq:
    #   Enumerator.product(*enums)                   -> enum
    #   Enumerator.product(*enums) { |*args| block } -> return value of args[0].each_entry {}
    def Enumerator.product(*enums, **nil, &block)
     # TODO: size should be calculated if possible
      return to_enum(__method__, *enums) if block.nil?
    
      enums.reverse.reduce(block) { |inner, enum|
        ->(*values) {
          enum.each_entry { |value|
            inner.call(*values, value)
          }
        }
      }.call()
    end
    
  • Not to be confused with Enumerator.produce. 😝

Prior case


Related issues 1 (1 open0 closed)

Is duplicate of Ruby master - Feature #7444: Array#product_setAssignedmatz (Yukihiro Matsumoto)Actions
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0