Практическое правило - используйте функцию, наиболее подходящую для ваших нужд.
Если вы просто хотите , ключи и не планируют когда - либо читал какой - либо из значений, используйте кнопки ():
foreach my $key (keys %hash) { ... }
Если вам просто нужны значения, используйте values ():
foreach my $val (values %hash) { ... }
Если вам нужны ключи и значения, используйте each ():
keys %hash; # reset the internal iterator so a prior each() doesn't affect the loop
while(my($k, $v) = each %hash) { ... }
Если вы планируете изменять ключи хеша любым способом, кроме удаления текущего ключа во время итерации, то вы не должны использовать each (). Например, этот код для создания нового набора заглавных букв с удвоенными значениями отлично работает с помощью keys ():
%h = (a => 1, b => 2);
foreach my $k (keys %h)
{
$h{uc $k} = $h{$k} * 2;
}
создание ожидаемого результирующего хеша:
(a => 1, A => 2, b => 2, B => 4)
Но используя each (), чтобы сделать то же самое:
%h = (a => 1, b => 2);
keys %h;
while(my($k, $v) = each %h)
{
$h{uc $k} = $h{$k} * 2; # BAD IDEA!
}
дает неверные результаты трудно предсказуемым образом. Например:
(a => 1, A => 2, b => 2, B => 8)
Однако это безопасно:
keys %h;
while(my($k, $v) = each %h)
{
if(...)
{
delete $h{$k}; # This is safe
}
}
Все это описано в документации perl:
% perldoc -f keys
% perldoc -f each
Одна вещь, о которой вы должны знать при использовании,
each
- это то, что у нее есть побочный эффект добавления «состояния» к вашему хешу (хеш должен помнить, что такое «следующий» ключ). При использовании кода, подобного приведенным выше фрагментам, который перебирает весь хэш за один раз, это обычно не проблема. Однако вы столкнетесь с трудно обнаруживаемыми проблемами (я говорю по опыту;) при использованииeach
вместе с такими операторами, какlast
илиreturn
для выхода изwhile ... each
цикла до того, как вы обработали все ключи.В этом случае хеш запомнит, какие ключи он уже вернул, и когда вы используете
each
его в следующий раз (возможно, в совершенно несвязанном фрагменте кода), он продолжит работу с этой позиции.Пример:
Это печатает:
Что случилось с клавишами bar и baz? Они все еще там, но второй
each
начинается там, где остановился первый, и останавливается, когда достигает конца хэша, поэтому мы никогда не видим их во втором цикле.источник
Место , где
each
может вызвать проблемы в том , что это правда, не Scoped итератора. В качестве примера:Если вам нужно быть уверенным, что он
each
получает все ключи и значения, вам нужно убедиться, что вы сначала используетеkeys
илиvalues
(так как это сбрасывает итератор). См. Документацию для каждого .источник
Использование синтаксиса each предотвратит одновременное создание всего набора ключей. Это может быть важно, если вы используете связанный хэш с базой данных с миллионами строк. Вы же не хотите создавать сразу весь список ключей и исчерпывать свою физическую память. В этом случае каждый служит итератором, тогда как ключи фактически генерируют весь массив перед запуском цикла.
Таким образом, единственное место, где "каждый" действительно используется, - это когда хэш очень большой (по сравнению с доступной памятью). Это может произойти только в том случае, если сам хеш не находится в памяти, если только вы не программируете портативное устройство сбора данных или что-то с небольшим объемом памяти.
Если память не является проблемой, обычно парадигма карты или ключей является более распространенной и простой для чтения парадигмой.
источник
Несколько разных мыслей по этой теме:
values
возврат псевдонимов, что означает, что их изменение приведет к изменению содержимого хэша. Это сделано намеренно, но в некоторых случаях это может быть не так.each
. Это не верно для ,keys
какeach
это итератор , аkeys
возвращает список.источник
Я тоже всегда использую метод 2. Единственное преимущество использования каждого из них состоит в том, что если вы просто читаете (а не повторно назначаете) значение записи хэша, вы не будете постоянно разыменовывать хэш.
источник
Меня это может укусить, но я думаю, что это личное предпочтение. Я не могу найти никаких ссылок в документах на то, что each () отличается от keys () или values () (кроме очевидного ответа «они возвращают разные вещи». На самом деле в документах указано, что используется один и тот же итератор, и все они возвращать фактические значения списка вместо их копий, и то, что изменение хэша во время итерации по нему с использованием любого вызова - это плохо.
При этом я почти всегда использую keys (), потому что для меня обычно более самодокументируется доступ к значению ключа через сам хеш. Я иногда использую values (), когда значение является ссылкой на большую структуру, а ключ к хешу уже был сохранен в структуре, после чего ключ является избыточным и мне он не нужен. Думаю, я использовал each () 2 раза за 10 лет программирования на Perl, и, вероятно, оба раза это был неправильный выбор =)
источник
Я обычно использую
keys
и не могу вспомнить, когда в последний раз использовал или читал об использованииeach
.Не забывайте
map
, в зависимости от того, что вы делаете в цикле!источник
Я скажу:
Это дает 2 основных преимущества:
Я не думаю, что использовать ключи для каждого из них дороже, поэтому нет необходимости в двух разных конструкциях для одного и того же в вашем коде.
источник
keys
использовании памяти увеличивается наhash-size * avg-key-size
. Учитывая, что размер ключа ограничен только памятью (поскольку они просто элементы массива, такие как «их» соответствующие значения под капотом), в некоторых ситуациях это может быть недопустимо дороже как с точки зрения использования памяти, так и с точки зрения времени, затрачиваемого на создание копии.