Как создать массив хэшей и перебрать их в цикле в Perl?

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

for  ($i = 0; $i<@pattern; $i++){
  while(($k, $v)= each $pattern[$i]){
    debug(" $k: $v");
  }
}

person Marius    schedule 24.08.2009    source источник


Ответы (3)


Во-первых, почему вы не use strict и warnings? Следующие строки должны быть в начале каждой создаваемой вами Perl-программы, сразу после #!/usr/bin/perl. Всегда.

use strict;
use warnings;

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

Во-вторых, почему вы не делаете этого:

for my $i (@pattern) {
  ..
}

Это перебирает каждый элемент в @pattern, назначая их $i по одному. Затем в вашем цикле, когда вам нужен определенный элемент, просто используйте $i. Изменения в $i будут отражены в @pattern, а когда цикл завершится, $i выйдет из области видимости, по сути подчистив себя.

В-третьих, из любви к Ларри Уоллу, пожалуйста, объявите свои переменные с помощью my, чтобы локализовать их. На самом деле это не так сложно, и это сделает тебя лучше, обещаю.

В-четвертых, и последнее, в вашем массиве хранятся ссылки на хэши, а не хэши. Если бы они хранили хэши, ваш код был бы неправильным, потому что хэши начинаются с %, а не $. Как бы то ни было, ссылки (любого вида) являются скалярными значениями и, таким образом, начинаются с $. Поэтому нам нужно разыменовать их, чтобы получить хэши:

for my $i (@pattern) {
  while(my($k, $v) = each %{$i}) {
    debug(" $k: $v");
  }
}

Или по-вашему:

for  (my $i = 0; $i<@pattern; $i++) { # added a my() for good measure
  while(my($k, $v) = each %{$pattern[$i]}) {
    debug(" $k: $v");
  }
}
person Chris Lutz    schedule 24.08.2009
comment
Ха-ха, спасибо за ваш ответ, даже если мне пришлось многое прочитать, чтобы добраться туда :p То, что я искал, было %{$i} (или %{$_}, чтобы восстановить часть моей чести Perl). - person Marius; 24.08.2009
comment
К сведению, скобки не являются строго необходимыми — в этом случае вы можете написать %$i. Причина, по которой я использовал скобки, заключается в том, что если вы получаете более сложные, чем просто $i, они вам нужны: %{$pattern[$i]} не может быть записано как %$pattern[$i], потому что второе неоднозначно. - person Chris Lutz; 24.08.2009

Попробуйте это вместо этого:

for my $hashref (@pattern) {
    for my $key (keys %$hashref) {
        debug "$key: $hashref->{$key}";
    }
}

Самой большой проблемой с тем, что вы пытались сделать, было each $pattern[$i]. Функция each ожидает, что хеш будет работать, но $pattern[$i] возвращает хэш-ссылку (т. е. ссылка на хеш). Вы можете исправить свой код, разыменовав $pattern[$i] как хеш:

while(my($k, $v) = each %{$pattern[$i]}) {

Кроме того, остерегайтесь каждой функции, она может оставить итератор хэша в незавершенном состоянии.

person Chas. Owens    schedule 24.08.2009
comment
Опереди меня на 11 секунд. Возможно, мне следует меньше болтать. - person Chris Lutz; 24.08.2009
comment
Стараюсь писать быстро, потом возвращаюсь и блуждаю. - person Chas. Owens; 24.08.2009
comment
Это хорошая стратегия. Воистину, мне нужно многому научиться. Кроме того, интересная статья о том, почему each() это плохо. Мне нравится твоя отсылка к Звездным войнам. - person Chris Lutz; 24.08.2009
comment
Функция each не столько плоха, сколько опасна. И функция keys тоже не совсем безопасна: my @keys = keys %hash. Что произойдет, если %hash является связанной базой данных, которая содержит во много раз больше памяти? В этом случае while (my ($key, $val) = each %hash) {} явно лучше. - person Chas. Owens; 24.08.2009

См. документацию к кулинарной книге структур данных perl: perldoc perldsc

person William Pursell    schedule 24.08.2009