1

すでにこれに非常に似た質問がありますが、複数のアレイに対してこれを実行したいと思います。配列の配列があります。

my @AoA = (
    $arr1 = [ 1, 0, 0, 0, 1 ],
    $arr2 = [ 1, 1, 0, 1, 1 ],
    $arr3 = [ 2, 0, 2, 1, 0 ]
);

3つ(またはそれ以上)の配列すべての項目を合計して、次のような新しい配列を取得したい

( 4, 1, 2, 2, 2 )

use List::MoreUtils qw/pairwise/は2つの配列引数が必要です。

@new_array = pairwise { $a + $b } @$arr1, @$arr2;

頭に浮かぶ解決策の1つは、最初の2つの配列をループして関数に@AoA渡すことです。以降の反復では、次の入力とをペアワイズ関数に渡します。配列の奇数サイズの配列の場合、最後のを渡した後、0の要素を持つ同じサイズの配列を渡します。pairwise@$arr@AoA@new_array@$arr@AoA

これは良いアプローチですか?もしそうなら、どうすればこれを実装できますか?ありがとう

4

4 に答える 4

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

簡単なテスト:

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

上記はすべて、すべてのアレイが同じ長さであると想定しています。


スニペットに関するメモ:

配列構造の例はもちろん合法的なperlであり、意図したとおりに実行されますが、内部の割り当てを省略するのが最善です。

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

あなたは実際にPDL、Perlデータ言語を探しているかもしれません。Perl用の数値配列モジュールです。データの配列を処理するための多くの機能があります。他の言語の他の数値配列モジュールとは異なり、任意の次元でその機能を使用するこの便利な機能があり、あなたが意味することを実行します。これはすべて経営幹部レベルで行われるため、効率的かつ高速であることに注意してください。

あなたの場合sumover、N次元のオブジェクトを取得し、最初の次元を合計して作成されたN-1次元のオブジェクトを返す投影メソッドを探しています。あなたのシステムでは、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;
于 2013-03-25T02:43:19.837 に答える
2

これが単純な反復アプローチです。おそらく、大きなデータセットに対してはひどく機能します。よりパフォーマンスの高いソリューションが必要な場合は、データ構造を変更するか、CPANで統計パッケージの1つを探す必要があります。以下は、すべての配列が最初の配列と同じサイズであることを前提としています。

$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の各値は数値になります(具体的には、+ =演算子で「機能する」形式の値)。
  • 少なくとも1つの「列」が含まれる少なくとも1つの「行」があります

注:「$#{$ 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;
于 2013-03-25T02:06:02.837 に答える