3

perlプログラムに次の2つの同じサイズの配列があるとします。

my @arr1 = 1..5;
my @arr2 = 6..10;

reduceコアモジュールで定義された関数を使用してドット積を取得しようとしていList::Utilますが、以下が機能しません。

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

予想される130ではなく50を出力として取得します。

4

3 に答える 3

6

ドキュメントでは、の動作についてreduce次のように説明しています。

最初の呼び出しは$aと$bがリストの最初の2つの要素に設定され、後続の呼び出しは$ aを前の呼び出しの結果に設定し、$bをリストの次の要素に設定することによって行われます。

したがって、この場合、最初の反復でreduce設定され$a = 0$b = 1したがって、実行されます

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

この一時的な結果はたまたま20です。

ここで、2回目の反復で$aは、前の反復の結果などに設定され$a = 20ます$b = 2。したがって、以下が実行されます

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

これは私たちが望んでいることではありません。

考えられる回避策:

0次のように、入力として提供されたリストの先頭にイニシャルを追加reduceします。

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

これにより、最初の反復で望ましい結果が得られ、$a = $b = 0計算します。

0 + $arr[0] * $arr[0]

その結果は6になります。

次に、2回目の反復で、次の$a = 6 $b = 1ように計算します。

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

于 2013-01-15T21:54:43.973 に答える
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";
于 2020-05-09T01:07:17.270 に答える
0

本音をいうと、

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

最も読みやすいわけではありません。これがあります:

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

しかし、それは使用しませんreduce。ええと、List :: Utilを使用する代わりに、単純に実装sumすることができ、おそらくそれをインライン化することさえできます。reduce

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

ただし、これら3つのソリューションはどれも純粋関数型ではありません。

于 2013-01-16T00:04:14.687 に答える