Перебор хэша

Проблема

Требуется выполнить некоторые действия с каждым элементом (то есть парой «ключ/значение») хэша.

Решение

Воспользуйтесь функцией each в цикле while:
while ($КЛЮЧ, $ЗНАЧЕНИЕ) = each(%ХЭШ)) {
  # Сделать что-то с $КЛЮЧ и $ЗНАЧЕНИЕ
}
Если хэш не очень велик, можно вызвать keys в цикле fоreach:
foreach $КЛЮЧ (keys %ХЭШ) {
  $ЗНАЧЕНИЕ = $ХЭШ{$КЛЮЧ};
  # Сделать что-то с $КЛЮЧ и $ЗНАЧЕНИЕ
}

Комментарий

Следующий простой пример перебирает элементы хэша %food_color:
while(($food, $color) = each(%food_color)) {
  print "$food is $color.\n";
}
Banana is yellow.
Apple  is red.
Carrot is orange.
Lemon  is yellow.
В примере с foreach можно обойтись без переменной $color, поскольку она пользуется всего один раз. Достаточно написать:
print "$food is $food_color{$food}.\n".
При каждом вызове each для одного и того же хэша функция возвращает «следующую» пару ключ/значение. Слово «следующую» взято в кавычки, потому пары возвращаются в порядке, соответствующем внутренней структуре хэша этот порядок почти никогда не совпадает с числовым или алфавитным. За последним элементом each возвращает пустой список (); результат интерпретируется как ложный, и цикл while завершается.
В примере с foreach использована функция keys, которая строит список ключей из хэша еще перед началом выполнения цикла. Преимущество each заключается в том, что пары «ключ/значение» извлекаются по одной. Если хэш содержит много ключей, отказ от предварительного построения полного списка сответственно экономит память и время. Однако функция each не позволяет управлять порядком обработки пар.
Применение foreach и keys для перебора списка позволяет установить свой порядок обработки. Предположим, нам понадобилось вывести содержимое хэш в алфавитном порядке ключей:
foreach $food (sort keys %food_color) {
  print "$food is $food_color{$food}.\n";
}
Apple is red.
Banana is yellow.
Carrot is orange.
Lemon is yellow.
Подобное применение fоreach встречается довольно часто. Функция keys строит список ключей в хэше, после чего fоreach перебирает их. Если хэш состоит из большого числа элементов, возникает опасность, что возвращаемый keys список займет много памяти. Приходится выбирать между затратами памяти и возможностью обработки элементов в определенном порядке.
Поскольку функции keys, values и each используют одни и те же внутренние структуры данных, следует внимательно следить за чередованием вызовов этих функций или преждевременным выходом из цикла each. При каждом вызове keys или values текущая позиция each сбрасывается. Следующий фрагмент зацикливается и бесконечно выводит первый ключ, возвращаемый each:
while ( ($k,$v) = each %food_color) {
  print "Processing $k\n";
  keys %food_color;       # Возврат к началу %food_color
}
Модификация хэша во время его перебора в each или fоreach, как правило, сопряжена с опасностью. При добавлении или удалении ключей из хэша функция each ведет себя по-разному для связанных и несвязанных хэшей. Цикл fоreach перебирает заранее построенный список ключей, поэтому после начала цикла он ничего не знает о добавленных или удаленных ключах. Ключи, добавленные внутри цикла, не включаются автоматически в список перебираемых ключей, а удаленные внутри цикла ключи не удаляются из этого списка.
Программа countfrom читает файл почтового ящика и выводит количество сообщений от каждого отправителя. Отправитель определяется по строке From: (в этом отношении сценарий не очень интеллектуален, однако нас сейчас интересуют операции с хэшами, а не обработка почтовых файлов). Передайте имя почтового ящика в командной строке или используйте "-" для перенаправления.
#countfrom
$filename = $ARGV[0] || "-";
open (FILE, "<$filename")  or die "Can't open $filename : $!";
while (<FILE>) {
  if (/^From: (.*)/) { $from{$1}++ }
}
foreach $person (sort keys %from) {
  print "$person: $from{$person}\n";
}

См. также

Описание функции each и keys



2013-09-10 17:05:19

Proverte kod v komentariyah gde pro list tam oshibki detskie




Оставить комментарий:
Ваше Имя:
Email:
Антибот: *  
Ваш комментарий: