2012-04-24 9 views
16

Ich habe eine Datei mit einer Liste und eine Datei erstellen müssen, die jede Zeile mit der anderen vergleicht. dies zum Beispiel hat meine Datei:Wie kann ich in Perl alle möglichen Kombinationen einer Liste generieren?

AAA 
BBB 
CCC 
DDD 
EEE

Ich würde die endgültige Liste mag so aussehen:

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

Ich versuche, dies in Perl zu tun, für dieses erste Mal und ein bin mit kleine Probleme. Ich weiß, dass Sie ein Array erstellen müssen, und teilen Sie es dann, aber danach habe ich einige Probleme.

+0

Bitte posten Sie Ihre bisher Code. – tuxuday

Antwort

0
  1. nehmen erste Saite
  2. iterieren über Array von nächster Position
    1. befestigen nächste Zeichenfolge ursprüngliche Zeichenfolge zu Ende
  3. nächsten Zeichenfolge nehmen und gehe zurück 2
7
zu Schritt

Werfen Sie einen Blick auf Math::Combinatorics - Führen Sie Kombinationen und Permutationen auf Listen

Beispiel aus dem CPAN Kopieren:

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

Warum verwenden Sie nicht die Beispieldaten aus der Frage? – daxim

+1

@daxim: Intension war etwas Arbeit für OP verlassen. –

0

Wie wäre:

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

Ausgang:

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

Der Glob-Trick sollte immer von den verschiedenen Vorbehalten begleitet werden, wenn er fehlschlägt. – daxim

+1

@daxim: Meinst du den "Nebeneffekt" der übereinstimmenden Dateien im aktuellen Arbeitsverzeichnis? Wenn ja, ist das nicht vollkommen sicher, da er nicht '?', '[]' Oder '*' verwendet? – flesk

+1

All dies. Ich ärgere mich jetzt, die Vorbehalte sollten klar als Teil der Antwort dargelegt werden, nicht als rhetorische Fragen, die als Kommentar mit geringer Sichtbarkeit angebracht wurden. Es ist kein "Nebeneffekt", es passiert wirklich, die Modalisierung des Wortes ist falsch. Es ist nicht sicher: Offensichtlich hat der Nutzer in der Frage erfundene/anonymisierte Daten zur Verfügung gestellt und wird unter realen Bedingungen eine böse Überraschung erleben. SO sollten Antworten darauf abzielen, die Menschen nicht zum Scheitern zu bringen, sie sollten sich stets der Feinheiten und Risiken bewusst sein; Vor diesem Hintergrund habe ich diese Antwort jetzt abgelehnt, um M42 einen Anreiz zu geben, es zu verbessern. - Fortsetzung: – daxim

28

Verwendung Algorithm::Combinatorics. Der iteratorbasierte Ansatz ist vorzuziehen, um alles auf einmal zu erzeugen.

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

Ausgang:

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

Hier ist ein Hack mit 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"; 
} 

Der Ausgang:

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

P. S. Sie können Text::Glob::Expand oder String::Glob::Permute Module anstelle von einfach glob() verwenden, um die Einschränkung der übereinstimmenden Dateien im aktuellen Arbeitsverzeichnis zu vermeiden.

+4

Der Globtrick sollte immer von den verschiedenen Vorbehalten begleitet sein, wenn er fehlschlägt. – daxim

8

Es ist einfach, dies mit Rekursion zu schreiben.

Dieses Codebeispiel veranschaulicht.

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

bearbeiten

Ich entschuldige mich - ich war Permutationen statt Kombinationen zu erzeugen.

Dieser Code ist korrekt.

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

Ausgang

AAA BBB 
AAA CCC 
AAA DDD 
AAA EEE 
BBB CCC 
BBB DDD 
BBB EEE 
CCC DDD 
CCC EEE 
DDD EEE 
Verwandte Themen