Feature #7444
openArray#product_set
Description
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:
- 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.
-
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 :-)
-
[].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) == [[]]
.