0

我不知道我是否很好地面对这个问题。我有一个带有标识的文件,然后是 10 个带有数据库名称的标识的文件(每个 ID 相同,但文件之间不同)。我要做的是将这 10 个文件的所有 ID 与仅具有标识的文件匹配,除非先前已匹配标识。

这 10 个文件是这样的:

File 1:
Id   Data Data Data Database_name 
Id1  ...  ...  ...    GenBank
...
Id20 ...  ...   ...   GenBank

File 2: 
Id   Data  Data Data Database_name
Id2  ...   ...  ...     IMG
Id30 ...   ...  ...     IMG
...

对于每个文件,我将这两个值(Id 和 Database_name)放在一个双键散列中。使用此代码:

if ( -e "result_GenBank" ){
    print "Yes, it exist!!!! \n";
    open FILE,'<', "result_GenBank" or die "Error Importing GenBank";
    while (my $line=<FILE>){
        chomp ($line);
        my($ClustId, $M5, $Identity, $Evalue, $Bit_score, $Id, $Protein, $Specie, $DB ) = split /\t/g, $line; 

        $GenBank{$ClustId}{$DB}=1;
    }
    close FILE;
}

if ( -e "result_KEEG" ){
    print "Yes, it exist!!!! \n";
    open FILE,'<', "result_KEEG" or die "Error Importing KEEG";
    while (my $line=<FILE>){
        chomp ($line);
        my($ClustId, $M5, $Identity, $Evalue, $Bit_score, $Id, $Protein, $Specie, $DB ) = split /\t/g, $line; 

        $KEEG{$ClustId}{$DB}=1;
    }
    close FILE;
}

对于只有 Ids 的文件,我也把它放在一个散列中:

 open FILE,'<', "Ids" or die "No Input";
while (my $line=<FILE>){
    chomp ($line);
    $key=$line;
    $total_ID{$key} = 1;

}
close FILE;

现在,我需要一个循环,将每个双键哈希(Id 和 DB_name)与只有一个键(Id)的哈希进行比较。如果 Id 匹配,则打印 Id 和 Db_name,除非 Id 先前已匹配,以避免具有两个不同 Db_name 的相同 Id。

4

1 回答 1

1

首先,您声明要对 ID-DB 对进行重复数据删除,以便每个 ID 仅与一个 DB 相关联。因此我们可以走捷径做

$GenBank{$ClustId} = $DB;

在构建哈希时。

其次,The%GenBank%KEEGhash本质上是同一个数据结构的一部分。这些变量的命名表明您实际上希望它们成为更大散列中的条目。然后,我们还可以删除那些糟糕的代码重复:

use feature 'say'; use autodie;

my @files = qw/GenBank KEEG/; # the physical files have e "result_" prefix

my %tables;
for my $file (grep { -e "result_$_" } @files ) {
    say STDERR "The $file file was found";
    open my $fh, '<', "result_$file";

    while (<$fh>){
        chomp;
        my($ClustId, $M5, $Identity, $Evalue, $Bit_score, $Id, $Protein, $Specie, $DB ) = split /\t/; 
        $table{$file}{$ClustId} = $DB;
    }
}

但是等等:如果我们以后想统一 ID,我们可以将它们保存在同一个哈希中!此外,当前代码让给定 ID 的最后一个 DB 条目胜出;我们想改变它,以便记住第一个条目。这很容易//使用自 perl5 v10 以来可用的定义或运算符。

my %DB_by_ID;
for my $file (grep { -e "result_$_" } qw/GenBank KEEG/ ) {
    ...;
    while (<$fh>){
        ...;
        $DB_by_ID{$ClustId} //= $DB;
    }
}

我的第三点是您的 ID 文件代表一个数组,而不是哈希。如果要对Ids文件中的条目进行重复数据删除,通常最好使用uniqfrom List::MoreUtils

use List::MoreUtils 'uniq';

my @IDs;

open my $fh, "<", "Ids"; # no error handling neccessary with autodie
while (<$fh>) {
  chomp;
  push @IDs, $_;
}

@IDs = uniq @IDs;

我必须承认上面的代码看起来非常愚蠢。这就是为什么我们将使用File::Slurp

use List::MoreUtils 'uniq';
use File::Slurp;

my @IDs = uniq read_file('Ids', chomp => 1);

现在剩下要做的就是%DB_by_ID使用 中给出的 ID迭代表@IDs,并打印出结果。这看起来像

for my $id (@IDs) {
  if (not exists $DB_by_ID{$id}) {
    warn "no entry for ID=$id";
    next;
  }
  say join "\t", $id, $DB_by_ID{$id};
}
于 2013-07-18T11:46:59.207 回答