我注意到Math::Cartesian::Product返回一个祝福对象数组,而不是一个简单的数组数组。我不知道为什么。我实际上需要做一些额外的工作(unbless)才能使用结果......
3 回答
我最近向List::Gencartesian
添加了一个函数:
cartesian CODE LIST_of_ARRAYREF
cartesian
计算任意数量的数组引用的笛卡尔积,每个数组引用可以是任意大小。返回一个生成器use List::Gen 'cartesian'; my $product = cartesian {$_[0] . $_[1]} [qw/a b/], [1, 2]; print "@$product"; # 'a1 a2 b1 b2'
返回的“生成器”是一个惰性绑定数组,将在被要求时生成值。还有迭代和其他访问器方法:
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 ...
我不知道您将使用的集合有多大,但使用上述方法的优点是生成器的存储需求仍然存在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
它只计算集合的 6 个元素,并且不存储任何内容。
从示例中可以看出,cartesian
它本身的返回值是一个生成器对象,但该对象的后续返回值是传递给 coderef 的任何返回值cartesian
。所以如果你想要数组引用,它很简单:cartesian {\@_} ...
此外,您还需要做哪些额外的工作来处理受祝福的参考资料?一个祝福数组在任何意义上仍然是一个数组,除了ref
将返回的内容。如果您正在编写基于引用类型的开关逻辑,那么您应该使用Scalar::Util
's 。reftype
一种替代方法是模块Set::CrossProduct,它将产生普通的、未受祝福的数组引用:
use Set::CrossProduct;
my $iter = Set::CrossProduct->new([ \@foo, \@bar ]);
while (my $tuple = $iter->get){
...
}
或者一次获取所有元组:
my @tuples = $iter->combinations;
它祝福返回的数组,cartesian
以便在运行以下代码时
$b = $cartesian $a1, $a2;
$c = $cartesian $b, $a3;
...它可以检测到这$b
是先前调用模块的结果。
进行笛卡尔积运算是微不足道的,如果该模块返回的数据不符合您的需求,请考虑自己从头开始编写运算。
无论如何,检查模块源代码表明它并不太好。