Issue #7444 has been reported by marcandre (Marc-Andre Lafortune).

----------------------------------------
Feature #7444: Array#product_set
https://bugs.ruby-lang.org/issues/7444

Author: marcandre (Marc-Andre Lafortune)
Status: Open
Priority: Normal
Assignee: matz (Yukihiro Matsumoto)
Category: core
Target version: next minor


I'd like to propose `Array#product_set` to return the product set of arrays (aka cartesian product)

    deck = [1..13, %i(spades hearts diamond clubs)].product_set
        # => <#Enumerator ...>
    deck.first(2) # => [[1, :spades], [2, :spades]]

`product_set` would return an enumerator if no block is given. It should raise an error if an element of the array is not an Enumerable, like Array#transpose or #zip do.

Although `Array.product` would be acceptable too, I feel that an instance method of array is best in the case, in the same way that `transpose` is an instance method and not a class method.

The name "product_set" is a correct mathematical term. Although the synonym "cartesian_product" would also be acceptable, I propose "product_set" because it is shorter and cute too. I feel it is even clearer than `product`; the first time I head of `product` I was convinced that `[2,3,7].product # => 42`.

Addressing objections raised in #6499:

1) This is not for the sake of symmetry, but because often we have an array of the arrays we want a product of.

It is cumbersome to write `arrays.first.product(*arrays[1..-1])` or similar and it hides what is going on.

Writing `arrays.product_set` is much nicer.

2) The goal is not mainly to get a lazy version, but more to make the API better. The fact that it returns an Enumerator if no block is given is just a bonus :-)

3) [].product_set.to_a # => [[]]

This can be seen from a cardinality argument, or for example because `array.repeated_permutation(n) == Array.new(n, array).product_set.to_a` and `array.repeated_permutation(0) == [[]]`.



-- 
http://bugs.ruby-lang.org/