2012-04-24 20 views
16

Ho un file con un elenco e una necessità di creare un file che confronta ogni riga con l'altro. per esempio, il mio file ha questo:In Perl, come posso generare tutte le possibili combinazioni di un elenco?

AAA 
BBB 
CCC 
DDD 
EEE

vorrei che la lista finale di simile a questa:

AAA BBB 
AAA CCC 
AAA DDD 
AAA EEE 
BBB CCC 
BBB DDD 
BBB EEE 
CCC DDD 
CCC EEE 
DDD EEE

che sto cercando di fare questo in Perl, per questa prima volta e sto avendo un piccolo guaio. So che è necessario creare un array e quindi dividerlo, ma dopo ho qualche problema.

+0

Si prega di inviare il vostro codice finora. – tuxuday

risposta

0
  1. prendere prima stringa
  2. iterate su matrice da posizione successiva per terminare
    1. attribuiscono stringa successiva alla stringa originale
  3. prendere stringa successiva e tornare al passo 2
7

Dai uno sguardo allo Math::Combinatorics - Esegui combinazioni e permutazioni sugli elenchi

esempio la copia dal 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 
+3

Perché non usi i dati di esempio dalla domanda? – daxim

+1

@daxim: L'intensione doveva lasciare un po 'di lavoro per OP. –

0

ne dite:

#!/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; 

uscita:

(
    "AAABBB", 
    "AAACCC", 
    "AAADDD", 
    "AAAEEE", 
    "BBBCCC", 
    "BBBDDD", 
    "BBBEEE", 
    "CCCDDD", 
    "CCCEEE", 
    "DDDEEE", 
) 
+5

Il trucco glob deve essere sempre accompagnato dai vari avvertimenti per quando fallisce. – daxim

+1

@daxim: Intendi l'effetto collaterale dei file corrispondenti nella directory di lavoro corrente? Se è così, non è perfettamente sicuro dato che non sta usando '?', '[]' O '*'? – flesk

+1

Tutto ciò. Sono infastidito ora, i caveat dovrebbero essere chiaramente definiti come parte della risposta, non le domande retoriche allegate come un commento con scarsa visibilità. Non è un "effetto collaterale", accade davvero, la modalizzazione della parola è sbagliata. Non è sicuro: ovviamente l'utente ha fornito dati truccati/resi anonimi nella domanda e si troverà in una brutta sorpresa in condizioni reali. Le risposte SO dovrebbero sforzarsi di non mettere le persone al fallimento, dovrebbero essere sempre consapevoli delle sottigliezze e dei rischi; Detto questo, ho ora downvoted questa risposta per dare a M42 un incentivo per migliorarlo. - continua: – daxim

28

Usa Algorithm::Combinatorics. L'approccio basato su iteratore è preferibile per generare tutto in una volta.

#!/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"; 
} 

uscita:

AAA BBB 
AAA CCC 
AAA DDD 
AAA EEE 
BBB CCC 
BBB DDD 
BBB EEE 
CCC DDD 
CCC EEE 
DDD EEE
0

Ecco un hack utilizzando 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"; 
} 

L'output:

AAA BBB 
AAA CCC 
AAA DDD 
AAA EEE 
BBB CCC 
BBB DDD 
BBB EEE 
CCC DDD 
CCC EEE 
DDD EEE 

P.S. è possibile utilizzare i moduli Text::Glob::Expand o String::Glob::Permute anziché il normale glob() per evitare l'avvertenza dei file corrispondenti nella directory di lavoro corrente.

+4

Il trucco glob deve essere sempre accompagnato dai vari avvertimenti per quando fallisce. – daxim

8

È semplice scrivere questo utilizzando la ricorsione.

Questo esempio di codice dimostra.

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; 
} 

Modifica

Le mie scuse - mi è stato la generazione di permutazioni invece di combinazioni.

Questo codice è corretto.

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; 
} 

uscita

AAA BBB 
AAA CCC 
AAA DDD 
AAA EEE 
BBB CCC 
BBB DDD 
BBB EEE 
CCC DDD 
CCC EEE 
DDD EEE 
Problemi correlati