1

已经有一个与此非常相似的问题,但我想对多个数组执行此操作。我有一个数组数组。

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传递给函数。在随后的迭代中,我将把 next in和 the传递给 pairwise 函数。对于奇数大小的数组,在我传入最后一个in 之后,我将传入一个大小相等的数组,其中元素为 0。pairwise@$arr@AoA@new_array@$arr@AoA

这是一个好方法吗?如果是这样,我该如何实施?谢谢

4

4 回答 4

4

您实际上可能正在寻找PDL,即 Perl 数据语言。它是 Perl 的数值数组模块。它具有许多用于处理数据数组的功能。与其他语言的其他数值数组模块不同,它具有在任意维度上使用其功能的便捷能力,它会按照您的意思行事。请注意,这都是在 C 级别完成的,因此高效且快速!

在您的情况下,您正在寻找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]

返回 fromsumover是另一个 PDL 对象,如果你需要一个 Perl 列表,你可以使用list

print "$_\n" for $sum->list;
于 2013-03-25T02:43:19.837 回答
4

您可以轻松实现“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的 s。

快速测试:

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];

我更喜欢将数组作为引用传递,而不是使用\@or+原型:这允许你做

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];

以上都假设所有数组的长度相同。


关于您的片段的注释:

您的数组结构示例当然是合法的 perl,它甚至可以按预期运行,但最好省略内部分配:

my @AoA = (
    [ 1, 0, 0, 0, 1 ],
    [ 1, 1, 0, 1, 1 ],
    [ 2, 0, 2, 1, 0 ],
);
于 2013-03-25T01:43:45.093 回答
2

这是一个简单的迭代方法。对于大型数据集,它可能会表现得非常糟糕。如果您想要一个性能更好的解决方案,您可能需要更改数据结构,或在 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";
于 2013-03-25T01:43:07.433 回答
2

假设:

  • AoA 中的每一行都将具有与第一行相同的列数。
  • arrayrefs 中的每个值都是一个数字(具体来说,一个与 += 运算符一起“工作”的格式的值)
  • 将至少有一个“行”,其中至少有一个“列”

注意:“$#{$AoA[0]}”表示“数组的最后一个元素 ($#) 的索引,它是 @AoA 中的第一个数组引用 ({$AoA[0]})”

(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;
于 2013-03-25T02:06:02.837 回答