Я обнаружил, что хочу использовать формы оператора-модификатора итерации по хешам в Perl (v5):
my %h = (...);
do_something($_[0], $_[1]) for each %h; ### $_[0] => key, $_[1] => val
Или:
my %h = (...);
my @ary = %h;
do_something($_[0], $_[1]) for splice(@ary, 0, 2);
Конечно, ни одна из этих форм не существует. Просто любопытно, проводилась ли какая-либо работа по поддержке использования splice
или each
с формой модификатора операторов for
? В Perl 6 или через backport v5?
@melpomene Хорошее замечание, я обновил сообщение, чтобы поставить each
на одну ногу с splice
for each %h
уже делает что-то еще: each
возвращает список из двух элементов (ключ, значение), а for
выполняет итерацию по нему.
Под «модификатором оператора» вы имеете в виду функцию do_something(...)
, которая изменяет значения $_[0]
и $_[1]
?
@mob: Под «модификатором оператора» я подразумеваю синтаксис Perl, описанный здесь: perldoc.perl.org/perlsyn.html#Statement-Modifiers
В List :: Util и List :: MoreUtils есть несколько отличных функций, которые могут помочь в подобных ситуациях. В частности, обратите внимание на pairs
:
use List::Util qw{pairs};
do_something($_->[0], $_->[1]) foreach pairs %h;
Или, если вы можете переварить карту в пустом контексте:
use List::Util qw{pairmap};
pairmap { do_something($a, $b) } %h;
Ах, List :: Util, я должен был знать :) Я также придумал следующее, что тоже работает: do_something($_->[0], $_->[1]) for map { CORE::state @bob; push @bob, $_; @bob % 2 ? () : do {my @tmp = @bob; @bob = (); \@tmp} } %h
(Может, List :: Utils :: pair делает что-то похожее за кулисами?) Я просто хочу посмотреть, что другие придумать, поэтому я оставлю его открытым в другой день. В противном случае ваш ответ кажется приемлемым.
@textral, do {my @tmp = @bob; @bob = (); \@tmp}
- это длинный способ записи [splice(@bob)]
. И ваше решение терпит неудачу (т.е. плохо), если предоставлено нечетное количество аргументов.
Самое чистое решение - следующее:
do_something($_, $h{$_}) for keys %h;
Если вы хотите сэкономить память, вы можете использовать each
как обычно.
{ my ($k, $v); do_something($k, $v) while ($k, $v) = each(%h); }
Конечно, это намного чище без использования модификатора оператора.
while (my ($k, $v) = each(%h)) { do_something($k, $v); }
Наконец, если вы на самом деле не имеете дело с хешем, можно использовать pairs
из List :: Util.
use List::Util qw( pairs );
do_something(@$_) for pairs %h;
Этот последний подход очень расточителен, поскольку неэффективно создает множество массивов.
Да, верно: я использовал вашу первую форму раньше ... не знаю, почему я не подумал об этом на этот раз. И хотя это, вероятно, лучший способ, я думаю, что должен принять ответ @mwp, потому что мой исходный вопрос (хотя я сформулировал его плохо) был больше о том, как потреблять более одного элемента за раз из списка с использованием модификаторов оператора цикла . Я понимаю, что технически Perl (в настоящее время?) Не допускает этого, но, по крайней мере, List::Util::pairs
производит «впечатление» именно этого (и @mwp первым опубликовал информацию о List::Util::pairs
).
Обратите внимание, что вы все еще можете использовать each
, как всегда.
И я не уверен, почему вы говорите, что использование pairs
- это решение mwp; Я также предложил это, и я даже предложил более простой способ его использования.
@mwp отправил pairs
в качестве ответа за 8 часов до вас. Но да, ваше расширение @$_
ссылки на массив, возвращаемое pairs
, проще для глаз, чем использование mwp
Что касается "отправил пары в качестве ответа за 8 часов до того, как вы это сделали.", я знал об этом. Я просто указал, что дважды вы писали, что принимаете ответ mwp, потому что они использовали pairs
, что не имеет смысла.
небольшое улучшение вашего решения while
: do_something(@_) while @_ = each %h
Это очень опасно, и этого следует избегать
Хорошо, хотя установка элементов @_
опасна, установка @_
в целом таким образом - нет. Тем не менее, возиться с глобальными переменными - особенно с такой особенной - нельзя.
это безопаснее? do_something(@_) while local @_ = each %h
local
здесь ничего не делает, потому что нет никаких завитушек, которые его ограничивали.
извините, что откопал старый пост, но с тех пор я тестировал do_something(@_) while local @_ = each %h
, и он работает: все, что назначено для @_
до запуска команды, остается в @_
после запуска команды
@textral, хорошо, но он все еще не читается (неинтуитивно, неожиданное поведение), и он по-прежнему использует each
, который плохо справляется с проблемами.
Вы можете сократить
{my ($k, $v); do_something($k, $v) while ($k, $v) = each(%h); }
к
do_something($a, $b) while ($a, $b) = each %h;
поскольку $ a и $ b уже объявлены для сортировки.
each
даже не шлейф.