开发者

Why does Perl's shift complain 'Type of arg 1 to shift must be array (not grep iterator).'?

I've got a data structure that is a hash that contains an array of hashes. I'd like to reach in there and pull out the first hash that matches a value I'm looking for. I tried this:

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

But that gives me this error: Type of arg 1 to shift must be array (not grep iterator). I've re-read the perldoc for grep and I think what I'm doing ma开发者_如何学Ckes sense. grep returns a list, right? Is it in the wrong context?

I'll use a temporary variable for now, but I'd like to figure out why this doesn't work.


A list isn't an array.

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

… should do the job though. Take the return from grep in list context, but don't assign any of the values other than the first.


I think a better way to write this would be this:

use List::Util qw/first/;

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

Not only will it be more clear what you're trying to do, it will also be faster because it will stop grepping your array once it has found the matching element.


Another way to do it:

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

Note that the curlies around the first argument to grep are redundant in this case, so you can avoid block setup and teardown costs with

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

“List value constructors” in perldata documents subscripting of lists:

A list value may also be subscripted like a normal array. You must put the list in parentheses to avoid ambiguity. For example:

# 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];

As I recall, we got this feature when Randal Schwartz jokingly suggested it, and Chip Salzenberg—who was a patching machine in those days—implemented it that evening.

Update: A bit of searching shows the feature I had in mind was $coderef->(@args). The commit message even logs the conversation!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜