Question

I noticed Math::Cartesian::Product returns an array of blessed objects instead of a simple array of arrays. I couldn't figure out why. I actually need to do some extra work (unbless) to use the results...

Was it helpful?

Solution

One alternative is the module Set::CrossProduct, which will yield ordinary, unblessed array references:

use Set::CrossProduct;
my $iter = Set::CrossProduct->new([ \@foo, \@bar ]);

while (my $tuple = $iter->get){
    ...
}

Or get all tuples at once:

my @tuples = $iter->combinations;

OTHER TIPS

I added a cartesian function to List::Gen recently:

  • cartesian CODE LIST_of_ARRAYREF

    cartesian computes the cartesian product of any number of array refs, each which can be any size. returns a generator

    use List::Gen 'cartesian';
    my $product = cartesian {$_[0] . $_[1]} [qw/a b/], [1, 2];
    print "@$product"; # 'a1 a2 b1 b2'
    

The "generator" returned is a lazy tied array that will generate values when asked for them. There are also iterative and other accessor methods:

my $pairs = cartesian {@_} [qw/$ @ %/], ['a'..'z'], [1 .. 3];

while (my @tuple = $pairs->next) {  # $pairs->reset; #$pairs->index = 5; ...
    print @tuple, ', ';
}
# $a1, $a2, $a3, $b1, $b2, $b3, $c1, $c2, $c3, $d1, $d2, $d3, $e1 ...

I don't know how large the sets you will be working with are, but the advantage to using the above approach is that the storage requirements for the generator remain O(1)

my $digits = cartesian {join '' => @_} ([0..9]) x 10;

say for @$digits[10**9 - 3 .. 10**9 + 3];

#   0999999998
#   0999999999
#   1000000000
#   1000000001
#   1000000002
#   1000000003

which calculates only 6 elements of the set, and stores nothing.

As you can see from the examples, the return value of cartesian itself is a generator object, but that object's subsequent return values are whatever the coderef passed to cartesian returns. So if you want array references, it's as simple as: cartesian {\@_} ...


Also, what extra work did you have to do to deal with the blessed reference? A blessed array is still an array in every sense except for what ref will return. If you are writing switch logic based on reference type, Scalar::Util's reftype is what you should use.

It blesses the arrays returned by cartesian so that when some code as the following is run

$b = $cartesian $a1, $a2;
$c = $cartesian $b, $a3;

... it can detect that $b is the result of a previous call to the module.

Doing a cartesian product operation is something trivial, if the data as returned by that module does not fit your needs, consider writting the operation yourself from scratch.

Anyway, inspecting the module source code reveals it is not too great.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top