来自perlfaq4:“如何置换列表的 N 个元素?” :
在 CPAN 上使用 List::Permutor 模块。如果列表实际上是一个数组,请尝试 Algorithm::Permute 模块(也在 CPAN 上)。它是用 XS 代码编写的,非常高效:
use Algorithm::Permute;
my @array = 'a'..'d';
my $p_iterator = Algorithm::Permute->new ( \@array );
while (my @perm = $p_iterator->next) {
print "next permutation: (@perm)\n";
}
为了更快的执行,你可以这样做:
use Algorithm::Permute;
my @array = 'a'..'d';
Algorithm::Permute::permute {
print "next permutation: (@array)\n";
} @array;
这是一个小程序,它生成每行输入中所有单词的所有排列。permute() 函数中包含的算法在 Knuth 的计算机编程艺术的第 4 卷(仍未出版)中进行了讨论,并且适用于任何列表:
#!/usr/bin/perl -n
# Fischer-Krause ordered permutation generator
sub permute (&@) {
my $code = shift;
my @idx = 0..$#_;
while ( $code->(@_[@idx]) ) {
my $p = $#idx;
--$p while $idx[$p-1] > $idx[$p];
my $q = $p or return;
push @idx, reverse splice @idx, $p;
++$q while $idx[$p-1] > $idx[$q];
@idx[$p-1,$q]=@idx[$q,$p-1];
}
}
permute { print "@_\n" } split;
Algorithm::Loops 模块还提供了 NextPermute 和 NextPermuteNum 函数,它们可以有效地找到数组的所有唯一排列,即使它包含重复值,也可以就地修改它:如果它的元素是反向排序的,那么数组是反向的,使其排序,并返回false;否则返回下一个排列。
NextPermute 使用字符串顺序和 NextPermuteNum 数字顺序,因此您可以像这样枚举 0..9 的所有排列:
use Algorithm::Loops qw(NextPermuteNum);
my @list= 0..9;
do { print "@list\n" } while NextPermuteNum @list;