Reputation: 19251
The following snippet searches for the index of the first occurrence of a value in an array. However, when the parentheses around $index are removed, it does not function correctly. What am I doing wrong?
my ($index) = grep { $array[$_] eq $search_for } 0..$#array;
Upvotes: 18
Views: 11896
Reputation: 11
Also, I think using grep just to find the first instance is a little inefficient since it still has to walk through and run the callback on every element of the array. Especially if your array is long, you may be better off writing a loop or else using List::MoreUtils as mentioned above.
Upvotes: 1
Reputation: 2897
grep
returns a list. When you put the scalar variable name inside parentheses, Perl treats that whole l-value as a list, so it assigns the first value in the list to that variable.
If you had other scalars in the parentheses, you'd get the second, third, etc values from grep
's return array in them:
my ($index, $foo, $bar) = grep { $array[$_] eq $search_for } 0..$#array;
Upvotes: 1
Reputation: 64909
The grep function behaves differently in list context and scalar context. This documented in perldoc -f grep
:
Evaluates the BLOCK or EXPR for each element of LIST (locally setting $_ to each element) and returns the list value consisting of those elements for which the expression evaluated to true. In scalar context, returns the number of times the expression was true.
You can duplicate this on your own with the poorly named wantarray function:
sub my_grep {
my $sub = shift;
my @return;
for my $item (@_) {
push @return if $sub->($item);
}
return @return if wantarray;
return scalar @return;
}
Upvotes: 5
Reputation: 118118
I think you are looking for first_index
from List::MoreUtils:
use List::MoreUtils qw( first_index );
# ...
my $index = first_index { $_ eq $search_for } @array;
Upvotes: 7
Reputation: 47829
The parentheses provide a list context for grep
. grep
will then actually return the list of elements for which the expression was true and not just the number of times the expression was true.
Upvotes: 8
Reputation: 30831
The parentheses change the context in which the grep
is evaluated from scalar context to list context. In scalar context grep
returns the number of times the expression was true. In list context it returns the elements for which the expression was true.
The following highlights the difference context makes:
my $x = grep {/foo/} @array; # the number of things that match /foo/
my ($x) = grep {/foo/} @array; # the first thing that matches /foo/
my @foo = grep {/foo/} @array; # all the things that match /foo/
my (@foo) = grep {/foo/} @array; # all the things that match /foo/
Upvotes: 44