使用Perl的reduce函数计算点积

4
假设我的perl程序中有以下两个大小相等的数组:
my @arr1 = 1..5;
my @arr2 = 6..10;

我想使用List::Util核心模块中定义的reduce函数来获取它们的点积,但以下方法对我无效:

my $dot_prod = reduce { $arr1[$a] * $arr2[$a] + $arr1[$b] * $arr2[$b] }0..$#arr1;

我得到的输出是50,而不是预期的130

3个回答

7

文档描述了reduce的行为如下:

第一次调用时,$a和$b设置为列表的前两个元素,随后的调用将通过将$a设置为上一次调用的结果,将$b设置为列表中的下一个元素来完成。

因此,在本例中,在第一次迭代中,reduce将设置$a = 0$b = 1,因此执行:

$arr1[0] * $arr2[0] + $arr1[1] * $arr2[1] 

这个临时结果恰好是20

现在,对于第二次迭代,$a被设置为上一次迭代的结果,因此$a = 20$b = 2。因此,将执行以下操作:

$arr1[20] * $arr2[20] + $arr1[2] * $arr2[2]

这并不是我们想要的。

一个可能的解决方法:

在提供给reduce作为输入的列表前面添加一个初始0,如下所示:

my $dot_prod = reduce { $a + $arr1[$b] * $arr2[$b] } 0, 0..$#arr1;       

这样做可以得到期望的结果,因为在第一次迭代中,$a = $b = 0,我们将计算。
0 + $arr[0] * $arr[0]

此处代码的结果将为6.

接着在第二次迭代中,我们将得到 $a = 6 $b = 1 ,因此我们会计算

6 + $arr1[1] * $arr2[1]

etc.


1
老实说,
my $dot_prod = reduce { $a + $arr1[$b] * $arr2[$b] } 0, 0..$#arr1; 

不是最易读的。这里有这个:

my $dot_prod = sum map { $arr1[$_]*$arr2[$_] } 0..$#arr1;

但这并不使用reduce。好吧,我们可以简单地用reduce来实现sum,而不是使用List::Util的,甚至可以内联它:

my $dot_prod = reduce { $a+$b } map { $arr1[$_]*$arr2[$_] } 0..$#arr1;

1
以下是以可运行程序形式发布的先前发布的解决方案:
my @arr1 = 1..3;
my @arr2 = 6..8;

use List::Util qw(reduce sum) ;

my $dot_prod0 = reduce { $a + $arr1[$b] * $arr2[$b] } 0,0..$#arr1;       #reduce

print "Dot product0 = ".$dot_prod0."\n";
my $dot_prod1 = sum map  { $arr1[$_]*$arr2[$_] } 0..$#arr1;              #sum map
print "Dot product1 = ".$dot_prod1."\n";
my $dot_prod2 = reduce { $a+$b } map { $arr1[$_]*$arr2[$_] } 0..$#arr1;  #reduce map
print "Dot product2 = ".$dot_prod2."\n";

这是我在七年前针对同一个问题发布的三个解决方案,逐字逐句地复制。甚至没有注明出处。这是不礼貌的行为,也违反了该网站的条款。我已经添加了一段介绍作为归属声明。 - ikegami

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接