2

我有一个包含大约 25000 条记录的文件,每条记录有超过 13 个条目是药物名称。我想为这些条目形成所有可能的配对组合。例如:如果一行有三个记录 A、B、C。我应该形成组合为 1) AB 2) AC 3)B C。下面是我从互联网上获得的代码,它仅适用于将单行分配给大批:

use Math::Combinatorics;

my @n = qw(a b c);
my $combinat = Math::Combinatorics->new(
  count => 2,
  data  => [@n],
);

while ( my @combo = $combinat->next_combination ) {
  print join( ' ', @combo ) . "\n";
}

我正在使用的代码,它不会产生任何输出:

open IN, "drugs.txt" or die "Cannot open the drug file";
open OUT, ">Combination.txt";

use Math::Combinatorics;

while (<IN>) {
  chomp $_;
  @Drugs = split /\t/, $_;
  @n = $Drugs[1];

  my $combinat = Math::Combinatorics->new(
    count => 2,
    data  => [@n],
  );

  while ( my @combo = $combinat->next_combination ) {

    print join( ' ', @combo ) . "\n";
  }
  print "\n";
}

你能建议我解决这个问题吗?

4

3 回答 3

1

数组中的所有对都可以直接计算。从您的问题中使用药物 A、B 和 C,您可能会认为它们形成一个方阵。

AA  AB  AC
BA  BB  BC
CA  CB  CC

您可能不想要“对角线”对 AA、BB 和 CC。请注意,其余元素是对称的。例如,元素 (0,1) 是 AB, (1,0) 是 BA。在这里,我再次假设这些是相同的,并且您不希望重复。

要从线性代数中借用一个术语,您需要上三角形。假设给定行上的每个药物名称都是唯一的,这样做可以通过构造消除重复项。下面是一个算法。

  1. 依次选择每种药物q就行。对于其中的每一个,执行步骤 2 和 3。
  2. 从紧随q的药物开始,然后对列表其余部分中的每种药物r ,执行步骤 3。
  3. 记录对 ( q , r )。
  4. 记录的列表是所有唯一对的列表。

在 Perl 中,这看起来像

#! /usr/bin/env perl

use strict;
use warnings;

sub pairs {
  my @a = @_;

  my @pairs;
  foreach my $i (0 .. $#a) {
    foreach my $j ($i+1 .. $#a) {
      push @pairs, [ @a[$i,$j] ];
    }
  }

  wantarray ? @pairs : \@pairs;
}

my $line = "Perlix\tScalaris\tHashagra\tNextium";
for (pairs split /\t/, $line) {
  print "@$_\n";
}

输出:

Perlix Scalaris
Perlix 哈希格拉
Perlix Nextium
斯卡拉里斯哈沙格拉
Scalaris Nextium
哈希格拉 Nextium
于 2012-06-12T13:33:15.670 回答
1

您设置@n为包含数组的第二个值的@Drugs数组,请尝试仅data => \@Drugs在 Math::Combinatorics 构造函数中使用。

另外,使用严格;使用警告;等等等等等等。

于 2012-06-12T05:20:30.930 回答
0

我以前为别人回答过类似的问题。对他们来说,他们有一个问题是如何将一个字母列表组合成所有可能的单词。

看看如何使用 Perl 从一组字母中生成单词列表。在其中,您将从我的答案ikegami的正确答案中看到使用Math::Combinatorics的示例。(他用正则表达式做了一些相当有趣的事情)。

我相信其中之一会引导您找到所需的答案。也许当我有更多时间时,我会专门针对您的问题来充实一个答案。我希望这个链接有帮助。

于 2012-06-12T14:10:33.533 回答