18

リストを含むファイルがあり、各行を他の行と比較するファイルを作成する必要があります。たとえば、私のファイルには次のものがあります。

AAA  
BBB  
CCC  
DDD  
EEE

最終的なリストを次のようにしたいと思います。

ああああああああ  
AAA CCC  
ああああああ  
ああええ  
BBB CCC  
BBB DDD  
BBB EEE  
CCC DDD  
CCC EEE  
DDD EEE

私はこれを初めて Perl でやろうとしていますが、少し問題があります。配列を作成してから分割する必要があることは知っていますが、その後、問題が発生しています。

4

7 に答える 7

30

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 CCC
ああああああ
ああええ
BBB CCC
BBB DDD
BBB EEE
CCC DDD
CCC EEE
DDD EEE
于 2012-04-24T14:48:22.723 に答える
9

再帰を使ってこれを書くのは簡単です。

このコード例は示しています。

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

編集

申し訳ありませんが、組み合わせではなく順列を生成していました。

このコードは正しいです。

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
于 2012-04-24T16:20:30.910 に答える
7

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
于 2012-04-24T14:33:36.017 に答える
1

を使用したハックを次に示し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

PS現在の作業ディレクトリ内のファイルが一致するという警告を回避するために、plain の代わりにText::Glob::ExpandorString::Glob::Permuteモジュールを使用することをお勧めします。glob()

于 2012-04-24T15:08:12.333 に答える
1

次の Perl モジュールのベンチマークを行いました。

  1. 数学::組み合わせ論
  2. アルゴリズム::組み合わせ論
  3. Cmb

ベンチマークは、OPが要求したこと、2つのアイテムの組み合わせを実行することで構成されていましたが、元の要求された5つ(AAA BBB CCC DDD EEE)だけでなく、単語のセットを最大10,000まで増やしました。

Math::Combinatorics のテストスクリプト

#!/usr/bin/env perl
use strict; use warnings;
use Math::Combinatorics;
my $strings = [qw(AAA BBB CCC DDD EEE) x 2000];
my $iter = new Math::Combinatorics (count => 2, data => $strings);
while (my @c = $iter->next_combination) {
    print "@c\n";
}

これにより、1 秒あたり最大 53,479 の組み合わせが生成されました。

Algorithm::Combinatorics のテスト スクリプト

#!/usr/bin/env perl
use strict; use warnings;
use Algorithm::Combinatorics qw(combinations);
my $strings = [qw(AAA BBB CCC DDD EEE) x 2000];
my $iter = combinations($strings, 2);
while (my $c = $iter->next) {
    print "@$c\n";
}

これにより、1 秒あたり最大 861,982 の組み合わせが生成されました。

Cmb のテスト スクリプト

#!/usr/bin/env perl
use strict; use warnings;
use Cmb;
my $strings = [qw(AAA BBB CCC DDD EEE) x 2000];
my $cmb = new Cmb { size_min => 2, size_max => 2 };
$cmb->cmb_callback($#$strings + 1, $strings, sub {
    print "@_\n";
    return 0;
});

これにより、1 秒あたり最大 2,940,882 の組み合わせが生成されました。

しかし、組み合わせを出力する必要があるだけの場合、Cmb は実際には上記よりもさらに高速に実行できます。

#!/usr/bin/env perl
use strict; use warnings;
use Cmb;
my $strings = [qw(AAA BBB CCC DDD EEE) x 2000];
my $cmb = new Cmb { size_min => 2, size_max => 2 };
$cmb->cmb($#$strings + 1, $strings);

これにより、1 秒あたり最大 3,333,000 の組み合わせが生成されました。

ベンチマークは、カーネル 3.10.0-1062.1.1.el7.x86_64 x86_64 の CentOS Linux リリース 7.7.1908 (コア) で dpv を使用し、Intel(R) Xeon(R) CPU E5-2699 v4 @ で Perl 5.16.3 を使用して実行されました 2.20GHz

于 2019-12-06T03:52:18.147 に答える
0
  1. 最初の文字列を取る
  2. 次の位置から最後まで配列を反復処理します
    1. 次の文字列を元の文字列に添付します
  3. 次の文字列を取り、ステップ2に戻ります
于 2012-04-24T14:32:36.740 に答える
0

どうですか:

#!/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",
)
于 2012-04-24T14:34:40.217 に答える