2013-07-10 2 views
3

У меня есть хэш, который должен содержать определенные ключи, которые связаны с их собственными массивами. Чтобы быть более конкретным, хеш-ключи являются значениями качества, а массивы - именами последовательностей. Если для этого качества уже существует массив, я бы хотел добавить имя последовательности в массив, связанный с соответствующим качеством. Если его нет, я хочу создать его и добавить к нему имя последовательности. Все это делается в цикле while, проходя через все последовательности один за другим.Perl, хэш массивов: добавление и удаление ключей, добавление в массив, все в цикле while

Я пытался делать такие вещи, как в Perl How do I retrieve an array from a hash of arrays?, но я не могу понять, как это правильно.

Я просто получаю эти сообщения об ошибках: Скалярное значение @ {хэша {$ Q} лучше записать как $ {хэша {$ д} на asdasd.pl линии 69. Глобальный символ "@q" требует явного пакета имя Asdasd .pl line 58. И некоторые другие тоже.

Вот пример того, что я пробовал:

my %hash; 
while (reading the sequences) { 
    my $q = "the value the sequence has"; 
    my $seq = "the name of the sequence"; 

    if (exists $hash{$q}) { 
     push (@{$hash{$q}}, $seq); 
    } else { 
     $hash{$q} = \@q; 
     $hash{$q} = [$seq]; 
     next; 
    } 
} 

Это, очевидно, не должна быть очень сложной проблемой, но я новичок в PERL и такого рода проблемы чувствует себя трудно. Я искал это из разных мест, но, похоже, я чего-то не понимаю, и это может быть действительно очевидно.

+1

массив '@ q' не определен. Пожалуйста, включите его в свой код. – shawnhcorey

+0

Умм, да, это нигде не определено, что может вызвать проблемы.Я все еще смущен, как вы можете (а иногда и нужно) переключаться с ‰ или @ на $ в разных ситуациях, не определяя ничего, иногда я получаю ошибки, а иногда я должен это делать. Во всяком случае, я получил это, чтобы работать с подсказкой, что мне действительно нужно заявление «push». – Vamii

+0

Пожалуйста, напишите рабочий код. В противном случае очень сложно ответить на ваши вопросы. – shawnhcorey

ответ

4

Вы можете использовать то, что perl звонит автообновление, чтобы сделать это довольно легко. Ваш код не нуждается в этом центральном if-statement. Вы можете варить его вниз:

push @{ $hash{$q} }, $seq; 

Если конкретный ключ еще не существует в хэш, Perl будет autoviv его, так как он может сделать вывод, что вы хотите ссылку на массив здесь.

Вы можете найти дополнительные ресурсы по автовивитации, выполнив поиск в Google. Это уникальное слово, которое подавляющее большинство хитов кажется актуальным. :-)

+0

Ох, как магия: так просто, и все же он делает именно то, что я хочу. Спасибо! – Vamii

2

Вы на самом деле очень близко, несколько замечаний, хотя:

  1. В вашем else блоке вы присвоить ссылку на @q в ваш хэш затем сразу переписать его с [$seq], только последняя операция по хеш будет содержать

  2. В конце вашего цикла вам не понадобится next, он автоматически перейдет к следующей итерации, если в цикле больше нет операторов.

Все остальное, кажется, работает хорошо, вот мои изменения и данные тестирования я использовал (так как я ничего о ДНК-последовательностей, не знаю, я просто использовал письма, которые я помню из средней школы биологии)

Входной файл:

A 1 
T 2 
G 3 
A 3 
A 2 
G 5 
C 1 
C 1 
C 2 
T 4 

Код:

use strict; 
use warnings FATAL => 'all'; 

# open file for reading 
open(my $fh, '<', 'test.txt'); 

my %hash; 
while (my $line = <$fh>) { # read a line 

    # split the line read from a file into a sequence name and value 
    my ($q, $seq) = split(/\s+/, $line); 

    if(exists $hash{$q}) { 
     push @{ $hash{$q} }, $seq; 
    } 
    else { 
     $hash{$q} = [$seq]; 
    } 
} 

# print the resulting hash 
for my $k (keys %hash) { 
    print "$k : ", join(', ', @{$hash{$k}}), "\n"; 
} 


# prints 
# A : 1, 3, 2 
# T : 2, 4 
# C : 1, 1, 2 
# G : 3, 5