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 (u开发者_如何学Gonbless) to use the results...
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 generatoruse 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.
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;
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.
精彩评论