2012-04-24 14 views
16

Tôi có một tệp có danh sách và cần phải tạo một tệp so sánh từng dòng với nhau. ví dụ, tập tin của tôi có này:Trong Perl, làm thế nào tôi có thể tạo ra tất cả các kết hợp có thể có của một danh sách?

AAA 
BBB 
CCC 
DDD 
EEE

Tôi muốn trong danh sách cuối cùng để trông như thế này:

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

Tôi cố gắng để làm điều này trong Perl, cho lần đầu tiên này và đang gặp một rắc rối nhỏ. Tôi biết rằng bạn cần phải tạo một mảng, và sau đó phân chia nó, nhưng sau đó tôi gặp một số rắc rối.

+0

Xin vui lòng gửi mã cho đến nay của bạn. – tuxuday

Trả lời

0
  1. mất chuỗi đầu tiên
  2. lặp qua mảng từ vị trí tiếp theo để chấm dứt
    1. đính kèm chuỗi bên cạnh chuỗi gốc
  3. mất chuỗi tiếp theo và quay lại bước 2
7

Hãy xem Math::Combinatorics - Thực hiện kết hợp và hoán vị trên danh sách

dụ copy từ 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

Tại sao bạn không sử dụng dữ liệu ví dụ từ câu hỏi? – daxim

+1

@daxim: Intension là để lại một số công việc cho OP. –

0

Làm thế nào về:

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

đầu ra:

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

Thủ thuật toàn cầu nên luôn luôn đi kèm với các cảnh báo khác nhau khi nó không thành công. – daxim

+1

@daxim: Bạn có nghĩa là "tác dụng phụ" của các tệp phù hợp trong thư mục làm việc hiện tại không? Nếu vậy, điều này có hoàn toàn an toàn vì anh ta không sử dụng '?', '[]' Hay '*'? – flesk

+1

Tất cả điều đó. Tôi bực mình bây giờ, những lời khuyên nên được trình bày rõ ràng như là một phần của câu trả lời, chứ không phải những câu hỏi hùng biện gắn liền như một bình luận với khả năng hiển thị thấp. Nó không phải là một "tác dụng phụ", nó thực sự xảy ra, điều chỉnh từ là sai. Nó không an toàn: rõ ràng là người dùng cung cấp dữ liệu được tạo sẵn/ẩn danh trong câu hỏi và sẽ có bất ngờ xấu trong điều kiện thực tế. SO câu trả lời nên cố gắng không đặt người lên cho thất bại, họ phải luôn luôn nhận thức được sự tinh tế và rủi ro; cho rằng, tôi đã downvoted câu trả lời này để cung cấp cho M42 một động cơ để cải thiện nó. - tiếp tục: – daxim

28

Sử dụng Algorithm::Combinatorics. Cách tiếp cận dựa trên trình vòng lặp là thích hợp hơn để tạo ra mọi thứ cùng một lúc.

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

Output:

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

Dưới đây là một hack sử dụng 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"; 
} 

Sản lượng:

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

T.B. bạn có thể muốn sử dụng các mô-đun Text::Glob::Expand hoặc String::Glob::Permute thay vì đồng bằng glob() để tránh báo trước các tệp phù hợp trong thư mục làm việc hiện tại.

+4

Thủ thuật toàn cầu nên luôn luôn đi kèm với các cảnh báo khác nhau khi nó không thành công. – daxim

8

Thật dễ dàng để viết điều này bằng cách sử dụng đệ quy.

Ví dụ mã này minh họa.

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

Sửa

lời xin lỗi của tôi - Tôi đã tạo ra hoán vị thay vì kết hợp.

Mã này là chính xác.

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

đầu ra

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