2013-07-18 4 views
0

Я не знаю, хорошо ли я столкнулся с этой проблемой. У меня есть файл с идентификаторами, а затем 10 файлов с некоторыми из этих идентификаторов с именем базы данных (то же самое для каждого идентификатора, но отличается между файлами). То, что я пытаюсь сделать, соответствует всем идентификаторам этих 10 файлов с файлом только с идентификаторами, за исключением случаев, когда идентификация была сопоставлена ​​ранее.Perl: Сравнить хеш-ключи вдоль нескольких хэшей

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

Для файла только с идентификаторами, я положил его в хэш:

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 и Db_name, за исключением случаев, когда идентификатор был сопоставлен ранее, чтобы избежать использования одного и того же идентификатора с двумя разными именами Db_names.

+0

Если вам не нужно печатать значения с одинаковыми идентификаторами, почему бы не сохранить все эти значения в одном хэше? – Suic

ответ

1

Во-первых, вы заявляете, что хотите дедуплицировать пары 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; 
    } 
} 

Но подождите: Если мы хотим объединить идентификаторы позже, мы можем просто сохранить их в том же хэш! Кроме того, текущий код позволяет последней записи БД для данного идентификатора выигрывать; мы хотим изменить это так, чтобы первая запись была запомнена. Это легко сделать с помощью // определенного оператора или оператора, доступного с 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 таблицы с идентификаторами данных в @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}; 
} 
+0

спасибо! Очень полезно. Я чувствую, что усложняю себя ... – user2245731

Смежные вопросы