我不知道我是否正好面对这个问题。我有一个带有标识的文件,然后有10个文件,其中一些带有数据库名称的标识(每个标识相同但文件之间不同)。我要做的是将这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_names具有相同的Id。
答案 0 :(得分:1)
首先,您声明要对ID-DB对进行重复数据删除,以便每个ID仅与一个DB关联。因此我们可以采取捷径并做
$GenBank{$ClustId} = $DB;
在建立哈希时。
其次,%GenBank
和%KEEG
哈希基本上是同一数据结构的一部分。这些变量的命名表明您实际上希望它们是更大哈希中的条目。然后,我们还可以删除那个可怕的代码重复:
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
文件中的条目进行重复数据删除,那么通常最好使用uniq
中的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};
}