Perl从两个2D数组中减去值

时间:2020-10-03 20:52:16

标签: arrays perl

我有以下脚本:

#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw(sum);

my @a1=([1,2,3],
        [4,5,6],
        [7,8,9]);

my @a2=([4,3],
        [2,1]);

my @subtracted;

for (my $i=0; $i<=$#a2; $i++){
    for (my $j=0; $j<=$#a2; $j++){
        my $subtraction=$a1[$i][$j] - $a2[$i][$j];
        print "$subtraction\n";
        my $abs=abs($subtraction);
        push(@subtracted, $abs);
    }
}
my $sum=sum(@subtracted);
my $average=$sum/@subtracted;
print "Average=$average\n";

exit;

此打印:

-3
-1
2
4
Average=2.5

这将减去以下引用的元素:

$a1[0][0] - $a2[0][0]
$a1[0][1] - $a2[0][1]
$a1[1][0] - $a2[1][0]
$a1[1][1] - $a2[1][1]

但是现在我需要它来做

$a1[1][1] - $a2[0][0]
$a1[1][2] - $a2[0][1]
$a1[2][1] - $a2[1][0]
$a1[2][2] - $a2[1][1]

并打印:

1
3
6
8
Average=4.5

因此,@ a2的元素是固定的,但@ a1的元素却移动了1行和1列(比较的元素数始终受@ a2中的元素数限制)。但是现在我完全被困住了,不知道如何去做。因此,预先感谢您的想法。

1 个答案:

答案 0 :(得分:1)

my $sum = 0;
for my $i (0..$#a2) {
   for my $j (0..$#{ $a2[0] }) {
      my $diff = $a1[$i+1][$j+1] - $a2[$i][$j];
      $sum += $diff;
   }
}

my $avg = $sum / ( @a2 * @{ $a2[0] } );
say "avg: $avg";

在评论中,您谈论要一个循环。目前尚不清楚这是什么意思,但我认为您的意思是想为每个可能的偏移量循环。

my $n = @a2;
my $m = @{ $a2[0] };

for my $ofs (0..$#a1-$#a2) {
   my $sum = 0;
   for my $i (0..$n-1) {
      for my $j (0..$m-1) {
         my $diff = $a1[$i+$ofs][$j+$ofs] - $a2[$i][$j];
         $sum += $diff;
      }
   }

   my $avg = $sum / ( $n * $m );
   say "ofs: $ofs, avg: $avg";
}

一个偏移量之和中的许多术语与上一个偏移量之和相同。

Illustration of common terms

如您所见,与从头计算总和相比,计算两个后续总和的增量所涉及的操作更少。我们可以利用它来优化大型阵列的解决方案。

my $n = @a2;
my $m = @{ $a2[0] };
my $nm = $n * $m;

my $sum = 0;
for my $i (0..$n-1) {
   for my $j (0..$m-1) {
      $sum -= $a2[$i][$j];
   }
}

for my $i (0..$n-2) {
   for my $j (0..$m-2) {
      $sum += $a1[$i][$j];
   }
}

for my $ofs (0..$#a1-$#a2) {
   $sum += $a1[ $_     + $ofs ][ ($m-1) + $ofs ] for 0..$n-2;
   $sum += $a1[ ($n-1) + $ofs ][ $_     + $ofs ] for 0..$m-2;
   $sum += $a1[ ($n-1) + $ofs ][ ($m-1) + $ofs ];

   my $avg = $sum / $nm;
   say "ofs: $ofs, avg: $avg";

   $sum -= $a1[ $_ + $ofs ][ 0  + $ofs ] for 1..$n-1;
   $sum -= $a1[ 0  + $ofs ][ $_ + $ofs ] for 1..$m-1;
   $sum -= $a1[ 0  + $ofs ][ 0  + $ofs ];
}

要处理大量数字,您可能需要查看PDL