Доступ к хеш-ссылке в perl

Мне интересно, можно ли сделать следующее в perl. Это сэкономит 40-50 строк кода.

У меня есть структура хэш-данных, например:

hash_Ref->{a}->{b}->{c}->{d}->{e}->{'count'}=30

Мне интересно, есть ли способ сделать следующее:

my $hash_ref_1 = ash_Ref->{a}->{b}->{c}->{d};

а затем используйте:

$hash_ref_2->{e}. 

Таким образом, я хочу сохранить хэш-ссылку до точки «x» в иерархии в переменной, а затем получить доступ к ссылке, на которую указывает точка «x». Я думаю, что это более ясно в примере выше.

Подробнее

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

 $VAR1 = {
          'e' => {
                   'count' => 2
                 },
          'c' => {
                   'count' => 2
                 },
          'a' => {
                   'count' => 2
                 },
          'b' => {
                   'count' => 2
                 },
          'd' => {
                   'count' => 2
                 }
        };

где я ожидал бы что-то вроде этого:

'a' => { 'count' => 2, 'b' => { 'count' => 2, 'c' => ......} }  

Вот код, который я использовал:

use strict;
use Data::Dumper;

my @array1 = ('a','b','c','d','e');
my @array2 = ('a','b','c','d','e');
my $hash;

 build_hash(\@array1);
 build_hash(\@array2);


sub build_hash {

    my @array = @{shift @_};

    my $hash_ref;

    for ( my $i =0 ;  $i < scalar @array ; $i++ ){

        print "$i \t $array[$i] \n";
         if ( exists $hash->{$array[$i]} ){

            $hash->{$array[$i]}->{'count'}++;
        }

        else{

            $hash->{$array[$i]}->{'count'}=1;
        }
    }
    print Dumper($hash);

}

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

Спасибо! -Абхи


person Abhi    schedule 31.05.2011    source источник
comment
Что вы пробовали? Это работает? Если нет, то почему? обязательны к прочтению perllol и perldsc   -  person    schedule 01.06.2011
comment
Просто комментарий к стилю: из perldoc perlreftut (p3rl.org/reftut) правило стрелки hash_Ref->{a}->{b}->{c}->{d}->{e}->{'count'} можно записать как hash_Ref->{a}{b}{c}{d}{e}{'count'}   -  person Joel Berger    schedule 01.06.2011
comment
почему $hash_ref_2 должно что-то содержать?   -  person Joel Berger    schedule 01.06.2011


Ответы (2)


# 'a' => { 'count' => 2, 'b' => { 'count' => 2, 'c' => ......} }

sub build_hash {
    $_[0] ||= {};
    my $hash = shift;
    for (@_) {
        $hash = $hash->{$_} ||= {};
        ++$hash->{count};
    }
}

build_hash($hash, @array1);
build_hash($hash, @array2);

Если вы хотите использовать автовивификацию, вы можете написать это следующим образом:

sub build_hash {
    my $p = \shift;
    for (@_) {
        $p = \( $$p->{$_} );
        ++$$p->{count};
    }
}

build_hash($hash, @array1);
build_hash($hash, @array2);

См. также: Data::Diver

person ikegami    schedule 31.05.2011
comment
@ikegami: Большое спасибо. Просто интересно, не могли бы вы порекомендовать какие-либо хорошие ресурсы, чтобы получить хорошее представление об этих методах в Perl. - person Abhi; 01.06.2011
comment
@Ahbi, ты всегда изменял один и тот же хэш. Вы хотели изменить другие хэши. Этих хэшей не существовало. Поэтому вам нужно было их создать. Ваша проблема не имеет ничего общего с Perl, поэтому никакая книга о методах Perl не поможет. - person ikegami; 01.06.2011
comment
@ikegami: я должен был быть более откровенным. Я хотел спросить о хорошем ресурсе по сложным структурам данных в Perl. Также не могли бы вы объяснить мне причину $_[0] ||= {}; в первой программе. Я наверняка что-то упускаю. - person Abhi; 01.06.2011
comment
@Abhi, в моей версии $hash не является глобальным. Если вы создадите хэш-ссылку в локальной переменной $hash (скажем, посредством автовивификации), это не повлияет на переменную в вызывающем объекте. С другой стороны, изменение $_[0] изменит переменную в вызывающей программе. - person ikegami; 01.06.2011
comment
@ikegami: большое спасибо за вашу помощь. вы определенно помогаете мне узнать новые вещи, которые я не знаю о perl. У меня есть еще один уточняющий вопрос о программе. Не могли бы вы объяснить, как будет работать строка $hash = $hash-›{$_} ||= {}. Таким образом, каждый раз, когда появляется новая запись, создается анонимный хеш, но как он попадает в основной большой хэш с иерархией. Я все еще в замешательстве в этой части. - person Abhi; 02.06.2011
comment
@Abhi, $hash = $hash->{$_} ||= {}; такое же, как $hash->{$_} ||= {}; $hash = $hash->{$_};. Слияния никогда не бывает, поскольку мы строим от корня к листу, а не от листа к корню. - person ikegami; 02.06.2011

Это должно работать так, как вы думаете, что это должно работать. В качестве примечания: иногда, когда у вас есть хэш хэша хэша... вам действительно нужен был один хэш с составным ключом, например $h{"$a,$b,$c"} вместо этого из $h{$a}{$b}{$c}. Просто кое-что, что нужно иметь в виду. Не знаю, применимо ли оно здесь.

person frankc    schedule 31.05.2011
comment
@frankc: я добавил некоторые подробности + полный код в свой исходный вопрос. - person Abhi; 01.06.2011
comment
@frankc: У меня нет подробностей, чтобы доказать это, но это звучит как пугающий и ненужный ключ, чтобы включить его в микс. Нет минусов, но я бы не использовал это! - person Joel Berger; 01.06.2011
comment
Вы думаете, что составной ключ труднее понять, чем 6-уровневую глубокую структуру данных? Я никогда не измерял его, но могу поспорить, что составной ключ также более эффективен. - person frankc; 01.06.2011
comment
На самом деле я думаю, что составное сложнее читать, чем вложенное лично, но давайте примем вашу предпосылку. Ты собираешься пообещать мне, что никогда не будешь использовать , в своих хеш-ключах. Я знаю, что это необычно, но что, если вы создадите на ее основе большую систему, и кто-то нарушит это обязательство, вся ваша структура данных сломается. В дальнейшем для его использования необходимо разделить ключи запятыми: лишняя ненужная работа. Что делать, если вы хотите добавить некоторые данные к одному из ключей; Раньше это был хэш, в него было легко добавить больше информации, теперь это часть списка, разделенного запятыми, а не отдельная единица! - person Joel Berger; 01.06.2011
comment
В конце концов, это не обязательно и не поможет здесь в любом случае. Так как он новичок, давайте не будем путать его с неблагоразумными уловками и научим его использовать правильный Perl. Он может облажаться позже, если захочет, когда будет знать, что делает. - person Joel Berger; 01.06.2011
comment
Еще одно: поиск по хэшу должен быть намного быстрее, чем ручной алгоритм извлечения, который вам придется написать, чтобы найти определенные элементы, которые будут подвержены ошибкам для необычных ключей или шаблонов. - person Joel Berger; 01.06.2011
comment
-1: поскольку в ваших обозначениях нельзя представить 'a' => { 'count' => 2, 'b' => { 'count' => 2, 'c' => ......} }, этот ответ даже не помогает ОП. - person Joel Berger; 01.06.2011
comment
Оп не уточнил свой вопрос до тех пор, пока я не опубликовал свой ответ, как отмечено оператором в комментарии выше. Нет необходимости обещать не использовать запятую, поскольку запятая является примером разделителя, а не правилом. Программист должен тщательно выбирать. Если вам часто нужен доступ к независимым частям ключа и приходится часто разделять, то это не правильный подход. Я не говорил, что это всегда правильный подход. Я считаю, что программистам можно доверять, чтобы они использовали свой мозг для поиска хорошего решения, а не использовали перепроектированные решения, стоимость которых перевешивает их преимущества. - person frankc; 01.06.2011