Перебор хэша
Проблема
Требуется выполнить некоторые действия с каждым элементом (то есть парой «ключ/значение») хэша.
Решение
Воспользуйтесь функцией 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
Proverte kod v komentariyah gde pro list tam oshibki detskie
Оставить комментарий:
|
|