В Perl, как я могу генерировать все возможные комбинации списка?
У меня есть файл со списком, и вам нужно сделать файл, который сравнивает каждую строку с другой. например, мой файл имеет следующее:
AAA
BBB
CCC
DDD
EEE
Я бы хотел, чтобы последний список выглядел так:
AAA BBB
AAA CCC
AAA DDD
AAA EEE
BBB CCC
BBB DDD
BBB EEE
CCC DDD
CCC EEE
DDD EEE
Я пытаюсь сделать это в Perl, для этого первого раза, и у меня небольшие проблемы. Я знаю, что вам нужно создать массив, а затем разбить его, но после этого у меня возникают проблемы.
Ответы
Ответ 1
Используйте Algorithm::Combinatorics. Подход, основанный на итераторе, предпочтительнее всего генерировать все сразу.
#!/usr/bin/env perl
use strict; use warnings;
use Algorithm::Combinatorics qw(combinations);
my $strings = [qw(AAA BBB CCC DDD EEE)];
my $iter = combinations($strings, 2);
while (my $c = $iter->next) {
print "@$c\n";
}
Вывод:
AAA BBB
AAA CCC
AAA DDD
AAA EEE
BBB CCC
BBB DDD
BBB EEE
CCC DDD
CCC EEE
DDD EEE
Ответ 2
Прямо написать это с помощью рекурсии.
Этот пример кода демонстрирует.
use strict;
use warnings;
my $strings = [qw(AAA BBB CCC DDD EEE)];
sub combine;
print "@$_\n" for combine $strings, 5;
sub combine {
my ($list, $n) = @_;
die "Insufficient list members" if $n > @$list;
return map [$_], @$list if $n <= 1;
my @comb;
for my $i (0 .. $#$list) {
my @rest = @$list;
my $val = splice @rest, $i, 1;
push @comb, [$val, @$_] for combine \@rest, $n-1;
}
return @comb;
}
Edit
Мои извинения - я генерировал перестановки вместо комбинаций.
Этот код правильный.
use strict;
use warnings;
my $strings = [qw(AAA BBB CCC DDD EEE)];
sub combine;
print "@$_\n" for combine $strings, 2;
sub combine {
my ($list, $n) = @_;
die "Insufficient list members" if $n > @$list;
return map [$_], @$list if $n <= 1;
my @comb;
for (my $i = 0; $i+$n <= @$list; ++$i) {
my $val = $list->[$i];
my @rest = @$list[$i+1..$#$list];
push @comb, [$val, @$_] for combine \@rest, $n-1;
}
return @comb;
}
Выход
AAA BBB
AAA CCC
AAA DDD
AAA EEE
BBB CCC
BBB DDD
BBB EEE
CCC DDD
CCC EEE
DDD EEE
Ответ 3
Взгляните на Math:: Combinatorics - Выполните комбинации и перестановки в списках
пример копирования из CPAN:
use Math::Combinatorics;
my @n = qw(a b c);
my $combinat = Math::Combinatorics->new(count => 2,
data => [@n],
);
print "combinations of 2 from: ".join(" ",@n)."\n";
print "------------------------".("--" x scalar(@n))."\n";
while(my @combo = $combinat->next_combination){
print join(' ', @combo)."\n";
}
print "\n";
print "permutations of 3 from: ".join(" ",@n)."\n";
print "------------------------".("--" x scalar(@n))."\n";
while(my @permu = $combinat->next_permutation){
print join(' ', @permu)."\n";
}
output:
combinations of 2 from: a b c
------------------------------
a b
a c
b c
permutations of 3 from: a b c
------------------------------
a b c
a c b
b a c
b c a
c a b
c b a
Ответ 4
- взять первую строку
- итерация по массиву из следующей позиции до конца
- присоединить следующую строку к исходной строке
- возьмите следующую строку и вернитесь к шагу 2
Ответ 5
Как насчет:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dump qw(dump);
my @in = qw(AAA BBB CCC DDD EEE);
my @list;
while(my $first = shift @in) {
last unless @in;
my $rest = join',',@in;
push @list, glob("{$first}{$rest}");
}
dump @list;
выход:
(
"AAABBB",
"AAACCC",
"AAADDD",
"AAAEEE",
"BBBCCC",
"BBBDDD",
"BBBEEE",
"CCCDDD",
"CCCEEE",
"DDDEEE",
)
Ответ 6
Здесь взломается glob
:
my @list = qw(AAA BBB CCC DDD EEE);
for my $i (0..$#list-1) {
print join "\n", glob sprintf "{'$list[$i] '}{%s}",
join ",", @list[$i+1..$#list];
print "\n";
}
Выход:
AAA BBB
AAA CCC
AAA DDD
AAA EEE
BBB CCC
BBB DDD
BBB EEE
CCC DDD
CCC EEE
DDD EEE
P.S. вы можете использовать Text::Glob::Expand
или String::Glob::Permute
вместо обычного glob()
, чтобы избежать предостережения совпадающих файлов в текущем рабочем каталоге.