私は数年前にこの正確な問題を解決しなければなりませんでした。私は自分の解決策を思いつくことができませんでしたが、代わりmap
に、再帰とともに巧妙かつ賢明に使用する次の素晴らしいコードに出くわしました。
#!/usr/bin/perl
print "permute:\n";
print "[", join(", ", @$_), "]\n" for permute([1,2,3], [4,5,6], [7,8,9]);
sub permute {
my $last = pop @_;
unless(@_) {
return map([$_], @$last);
}
return map {
my $left = $_;
map([@$left, $_], @$last)
}
permute(@_);
}
はい、これはクレイジーに見えますが、説明させてください! 関数@_
は空になるまで再帰し、その時点で([1], [2], [3])
(3 つの arrayref のリスト) を前のレベルの再帰に戻します。そのレベル$last
には、 を含む配列への参照があります[4, 5, 6]
。
$_
外側のマップの本体は、 set to [1]
、次に[2]
、最後にで 3 回実行され[3]
ます。(4, 5, 6)
次に、外側のマップの反復ごとに内側のマップが実行され([1, 4], [1, 5], [1, 6])
、 、([2, 4], [2, 5], [2, 6])
、および最後にが返されます([3, 4], [3, 5], [3, 6])
。
最後から 2 番目の再帰呼び出しは を返します([1, 4], [1, 5], [1, 6], [2, 4], [2, 5], [2, 6], [3, 4], [3, 5], [3, 6])
。
次に、その結果を に対して実行し[7,8,9]
ます。[1, 4, 7], [1, 4, 8], [1, 4, 9], [1, 5, 7], [1, 5, 8], [1, 5, 9], [1, 6, 7], [1, 6, 8], [1, 6, 9], [2, 4, 7], [2, 4, 8], [2, 4, 9], [2, 5, 7], [2, 5, 8], [2, 5, 9], [2, 6, 7], [2, 6, 8], [2, 6, 9], [3, 4, 7], [3, 4, 8], [3, 4, 9], [3, 5, 7], [3, 5, 8], [3, 5, 9], [3, 6, 7], [3, 6, 8], [3, 6, 9]
perlmonks.org に質問を投稿して、誰かに説明してもらったことを覚えています。
このソリューションを問題に簡単に適応させることができます。