Perl, хэш массивов: добавление и удаление ключей, добавление в массив, все в цикле while
У меня есть хеш, который должен содержать определенные ключи, которые связаны с их собственными массивами. Чтобы быть более точным, хэш-ключи - это значения качества, а массивы - имена последовательностей. Если для этого качества уже существует массив, я бы хотел добавить имя последовательности в массив, связанный с рассматриваемым качеством. Если его нет, я хочу создать его и добавить к нему имя последовательности. Все это делается в цикле while, проходя все последовательности по очереди.
Я пытался сделать что-то вроде Perl. Как получить массив из хэша массивов? но я не могу понять это правильно.
Я просто получаю эти сообщения об ошибках: Скалярное значение @{hash{$q} лучше записать как ${hash{$q} в строке 69 asdasd.pl. Глобальному символу "@q" требуется явное имя пакета asdasd.pl, строка 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, и такая проблема кажется сложной. Я гуглил это из разных мест, но, кажется, есть кое-что, чего я просто не понимаю, и это может быть действительно очевидным.
2 ответа
Вы можете использовать то, что perl называет автовивификацией, чтобы сделать это довольно легко. Вашему коду не нужен этот центральный оператор if. Вы можете свести это к:
push @{ $hash{$q} }, $seq;
Если конкретный ключ еще не существует в хэше, perl автоматически его активирует, так как он может заключить, что вам нужна ссылка на массив.
Вы можете найти дополнительные ресурсы по автовивификации, прибегнув к помощи Google. Это достаточно уникальное слово, которое кажется подавляющим большинством хитов.:-)
Вы на самом деле довольно близки, хотя несколько замечаний:
В вашем
else
заблокировать ссылку@q
в ваш хэш, то сразу же перезаписать его[$seq]
будет выполняться только последняя операция с хешемВам не нужно
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