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. Это достаточно уникальное слово, которое кажется подавляющим большинством хитов.:-)

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

  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
Другие вопросы по тегам