Почему сдвиг Perl жалуется на то, что «тип аргумента 1 для сдвига должен быть массивом (не итератором grep).»? - PullRequest
10 голосов
/ 29 марта 2010

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

   my $result = shift grep {$_->{name} eq 'foo'} @{$hash_ref->{list}};

Но это дает мне эту ошибку: Type of arg 1 to shift must be array (not grep iterator). Я перечитал perldoc для grep, и я думаю, что то, что я делаю, имеет смысл. grep возвращает список, верно? Это не в том контексте?

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

Ответы [ 3 ]

18 голосов
/ 29 марта 2010

Список не является массивом .

my ($result) = grep {$_->{name} eq 'foo'} @{$hash_ref->{list}};

... должен сделать работу, хотя. Возьмите возврат из grep в контексте списка, но не назначайте никакие значения, кроме первого.

17 голосов
/ 29 марта 2010

Я думаю, что лучший способ написать это было бы так:

use List::Util qw/first/;

my $result = first { $_->{name} eq 'foo' } @{ $hash_ref->{list} };

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

2 голосов
/ 29 марта 2010

Еще один способ сделать это:

my $result = (grep {$_->{name} eq 'foo'} @{$hash_ref->{list}})[0];

Обратите внимание, что в этом случае кривые вокруг первого аргумента для grep являются избыточными, поэтому вы можете избежать затрат на установку и демонтаж блока с помощью

my $result = (grep $_->{name} eq 'foo', @{$hash_ref->{list}})[0];

«Конструкторы значений списков» в perldata документы подписки на списки:

Значение списка также может быть подписано как обычный массив. Вы должны поставить список в скобках, чтобы избежать двусмысленности. Например:

# Stat returns list value.
$time = (stat($file))[8];

# SYNTAX ERROR HERE.
$time = stat($file)[8];  # OOPS, FORGOT PARENTHESES

# Find a hex digit.
$hexdigit = ('a','b','c','d','e','f')[$digit-10];

# A "reverse comma operator".
return (pop(@foo),pop(@foo))[0];

Насколько я помню, мы получили эту функцию, когда Рэндал Шварц в шутку предложил это, и Чип Зальценберг - который в те дни был патч-машиной - внедрил ее тем вечером .

Обновление: Небольшой поиск показывает, что я имел в виду $coderef->(@args). Сообщение коммита даже записывает разговор!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...