我有一个包含数字的二维数组。我试图计算出每个子阵列中的单个数字与每个其他子阵列中的一个相乘的乘积;然后,我需要为所有可能的组合执行此操作。
目的是我输入一个单独事件频率的文件,并获得这些事件发生的特定系列概率的输出,每组中有一个事件。
我在上一个问题的帮助下将一些代码混合在一起:
for my $aref ( getCartesian(@freq) ) {
my $p = 1;
foreach my $n (@$aref) {
$p = $p * $n;
}
print "$p\n";
}
sub getCartesian {
my @input = @_;
my @ret = map [$_], @{ shift @input };
for my $a2 (@input) {
@ret = map {
my $v = $_;
map [@$v, $_], @$a2;
}
@ret;
}
return @ret;
}
其中@freq
是一个数组数组,例如:
@freq = [0.1, 0.2, 0.3,]
[0.4, 0.5, 0.6,]
[0.7, 0.8, 0.9,]; `and ~ 20 more sub arrays`
这适用于小型测试文件,但是当我给它所需的24个子阵列输入时,每个项目有3个项目,组合的生成显然过于密集,有3 ^ 24种可能性。 我在一台22 GB RAM的机器上运行它,并且在任何输出之前4分钟后最大化。
我的问题是,如何修改代码以便我可以为每个组合打印出$p
,而不必将整个组合保存在内存中,从而杀死它。我认为时间是计算的唯一限制因素,而不是资源。
编辑:基础Perl中没有包的方法会很棒。遗憾的是,我没有HPC设施的管理员,
答案 0 :(得分:5)
Set::CrossProduct允许您遍历笛卡尔积,因此您无需将所有内容存储在内存中:
use List::Util qw(reduce);
use Set::CrossProduct;
my @array = (
[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6],
[0.7, 0.8, 0.9]
);
my $iterator = Set::CrossProduct->new(\@array);
while (my $tuple = $iterator->get) {
say '(', join(', ', @$tuple), '): ', reduce { $a * $b } @$tuple;
}
(0.1, 0.4, 0.7): 0.028
(0.1, 0.4, 0.8): 0.032
(0.1, 0.4, 0.9): 0.036
(0.1, 0.5, 0.7): 0.035
(0.1, 0.5, 0.8): 0.04
(0.1, 0.5, 0.9): 0.045
(0.1, 0.6, 0.7): 0.042
(0.1, 0.6, 0.8): 0.048
(0.1, 0.6, 0.9): 0.054
(0.2, 0.4, 0.7): 0.056
(0.2, 0.4, 0.8): 0.064
(0.2, 0.4, 0.9): 0.072
(0.2, 0.5, 0.7): 0.07
(0.2, 0.5, 0.8): 0.08
(0.2, 0.5, 0.9): 0.09
(0.2, 0.6, 0.7): 0.084
(0.2, 0.6, 0.8): 0.096
(0.2, 0.6, 0.9): 0.108
(0.3, 0.4, 0.7): 0.084
(0.3, 0.4, 0.8): 0.096
(0.3, 0.4, 0.9): 0.108
(0.3, 0.5, 0.7): 0.105
(0.3, 0.5, 0.8): 0.12
(0.3, 0.5, 0.9): 0.135
(0.3, 0.6, 0.7): 0.126
(0.3, 0.6, 0.8): 0.144
(0.3, 0.6, 0.9): 0.162