2012-04-24 32 views
16

Tengo un archivo con una lista y la necesidad de hacer un archivo que compare cada línea con la otra. por ejemplo, mi archivo tiene esto:En Perl, ¿cómo puedo generar todas las combinaciones posibles de una lista?

AAA 
BBB 
CCC 
DDD 
EEE

Me gustaría que la lista final para tener este aspecto:

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

que estoy tratando de hacer esto en Perl, para esta primera vez y estoy teniendo una pequeño problema Sé que necesitas hacer una matriz y luego dividirla, pero después de eso tengo algunos problemas.

+0

favor publicar su código hasta el momento. – tuxuday

Respuesta

0
  1. toman primera cadena
  2. iterar sobre matriz a partir de la siguiente posición para poner fin a
    1. adjuntar siguiente cadena a cadena original
  3. toman siguiente cadena y volver al paso 2
7

Eche un vistazo a Math::Combinatorics - Realice combinaciones y permutaciones en las listas

ejemplo copiar desde el 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

¿Por qué no utiliza los datos de ejemplo de la pregunta? – daxim

+1

@daxim: Intension debía dejar algo de trabajo para OP. –

0

¿Qué tal:

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

de salida:

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

El truco global siempre debe ir acompañado de varias advertencias para cuando falla. – daxim

+1

@daxim: ¿Quiere decir el "efecto secundario" de los archivos coincidentes en el directorio de trabajo actual? Si es así, ¿no es esto perfectamente seguro ya que no está usando '?', '[]' O '*'? – flesk

+1

Todo eso. Ahora estoy molesto, las advertencias deben ser claramente presentadas como parte de la respuesta, no como preguntas retóricas como un comentario con baja visibilidad. No es un "efecto secundario", realmente sucede, modalisar la palabra es incorrecto. No es seguro: obviamente, el usuario proporcionó datos inventados/anonimizados en la pregunta y será una mala sorpresa bajo las condiciones del mundo real. ASÍ QUE LAS RESPUESTAS DEBEN ESFUERZARSE PARA NO PREOCUPAR A LAS PERSONAS POR INCUMPLIMIENTO, DEBEN ESTAR ALREDEDOR DE SUTILEZAS Y RIESGOS dado que, ahora he declinado esta respuesta para darle a M42 un incentivo para mejorarla. - continued: – daxim

28

Uso Algorithm::Combinatorics. El enfoque basado en iteradores es preferible a generar todo a la vez.

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

Salida:

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

Aquí un corte usando 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"; 
} 

La salida:

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

P. S. Es posible que desee utilizar los módulos Text::Glob::Expand o String::Glob::Permute en lugar de simplemente glob() para evitar la advertencia de los archivos coincidentes en el directorio de trabajo actual.

+4

El truco global siempre debe ir acompañado de varias advertencias para cuando falla. – daxim

8

Escribir esto utilizando la recursión es sencillo.

Este ejemplo de código lo demuestra.

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

Editar

Mis disculpas - Yo estaba generando permutaciones en lugar de combinaciones.

Este código es correcto.

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

salida

AAA BBB 
AAA CCC 
AAA DDD 
AAA EEE 
BBB CCC 
BBB DDD 
BBB EEE 
CCC DDD 
CCC EEE 
DDD EEE 
Cuestiones relacionadas