[英]How to sum multiple arrays element-wise in Perl?
已经有一个与此非常相似的问题,但是我想针对多个阵列执行此操作。 我有一个数组数组。
my @AoA = (
$arr1 = [ 1, 0, 0, 0, 1 ],
$arr2 = [ 1, 1, 0, 1, 1 ],
$arr3 = [ 2, 0, 2, 1, 0 ]
);
我想对所有三个(或更多)数组的项求和以得到一个新的数组
( 4, 1, 2, 2, 2 )
use List::MoreUtils qw/pairwise/
需要两个数组参数。
@new_array = pairwise { $a + $b } @$arr1, @$arr2;
想到的一种解决方案是通过循环@AoA
和第一两个数组传递到pairwise
函数。 在随后的迭代中,我将@AoA
的下一个@$arr
和@new_array
@AoA
给@new_array
函数。 在数组大小为奇数的情况下,在传入@AoA
中的最后一个@$arr
@AoA
,我将传入元素为0的大小相等的数组。
这是一个好方法吗? 如果是这样,我该如何实现呢? 谢谢
您可以轻松实现“ n-wise”功能:
sub nwise (&@) # ← take a code block, and any number of further arguments
{
my ($code, @arefs) = @_;
return map {$code->( do{ my $i = $_; map $arefs[$_][$i], 0 .. $#arefs } )}
0 .. $#{$arefs[0]};
}
该代码有点丑陋,因为Perl不支持多维数组的切片。 相反,我使用嵌套的map
。
快速测试:
use Test::More;
my @a = (1, 0, 0, 0, 1);
my @b = (1, 1, 0, 1, 1);
my @c = (2, 0, 2, 1, 0);
is_deeply [ nwise { $_[0] + $_[1] + $_[2] } \@a, \@b, \@c], [4, 1, 2, 2, 2];
我更喜欢将数组作为引用传递,而不是使用\\@
或+
原型:这允许您执行
my @arrays = (\@a, \@b, \@c);
nwise {...} @arrays;
从List::MoreUtils
您还可以使用each_arrayref
:
use List::Util qw/sum/;
use List::MoreUtils qw/each_arrayref/;
my $iter = each_arrayref @arrays;
my @out;
while (my @vals = $iter->()) {
push @out, sum @vals;
}
is_deeply \@out, [4, 1, 2, 2, 2];
或者只是普通的旧循环:
my @out;
for my $i (0 .. $#a) {
my $accumulator = 0;
for my $array (@arrays) {
$accumulator += $array->[$i];
}
push @out, $accumulator;
}
is_deeply \@out, [4, 1, 2, 2, 2];
以上全部假设所有数组的长度相同。
片段中的注释:
数组结构的示例当然是Legal perl,它甚至可以按预期运行,但是最好省略内部分配:
my @AoA = (
[ 1, 0, 0, 0, 1 ],
[ 1, 1, 0, 1, 1 ],
[ 2, 0, 2, 1, 0 ],
);
您可能实际上正在寻找PDL (Perl数据语言)。 它是Perl的数值数组模块。 它具有处理数据数组的许多功能。 与其他语言的其他数值数组模块不同,它具有在任意维度上使用其功能的便捷功能,它将按您的意思进行操作。 请注意,这些都是在C级别完成的,因此它高效而快捷!
在您的情况下,您正在寻找投影方法sumover
,该sumover
将采用N维对象并返回通过对第一维求和而创建的N-1维对象。 由于在您的系统中要对第二个进行求和,我们首先必须通过交换尺寸0和1进行转置。
#!/usr/bin/env perl
use strict;
use warnings;
use PDL;
my @AoA = (
[ 1, 0, 0, 0, 1 ],
[ 1, 1, 0, 1, 1 ],
[ 2, 0, 2, 1, 0 ],
);
my $pdl = pdl \@AoA;
my $sum = $pdl->xchg(0,1)->sumover;
print $sum . "\n";
# [4 1 2 2 2]
sumover
的返回是另一个PDL对象,如果您需要Perl列表,则可以使用list
print "$_\n" for $sum->list;
这是一个简单的迭代方法。 对于大型数据集,它可能会执行得非常糟糕。 如果您想要性能更好的解决方案,则可能需要更改数据结构,或在CPAN上查找其中一个统计数据包。 下面假设所有数组的大小与第一个数组相同。
$sum = 0;
@rv = ();
for ($y=0; $y < scalar @{$AoA[0]}; $y++) {
for ($x=0; $x < scalar @AoA; $x++) {
$sum += ${$AoA[$x]}[$y];
}
push @rv, $sum;
$sum = 0;
}
print '('.join(',',@rv).")\n";
假设:
注意:“ $#{$ AoA [0]}”的意思是,“数组的最后一个元素($#)的索引,它是@AoA({$ AoA [0]})中的第一个arrayref”
(shebang)/usr/bin/perl
use strict;
use warnings;
my @AoA = (
[ 1, 0, 0, 0, 1 ],
[ 1, 1, 0, 1, 1 ],
[ 2, 0, 2, 1, 0 ]
);
my @sums;
foreach my $column (0..$#{$AoA[0]}) {
my $sum;
foreach my $aref (@AoA){
$sum += $aref->[$column];
}
push @sums,$sum;
}
use Data::Dumper;
print Dumper \@sums;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.