You want the first element in the list (or its index) that passes a test. Alternatively, you want to know whether any element passes the test. The test can be simple identity (“Is this element in the list?”)[7] or more complex (“I have a list of Employee objects, sorted from highest salary to lowest. Which manager has the highest salary?”). Simple cases normally only require the value of the element, but when the array itself will be altered, you probably need to know the index number of the first matching element.
To find a matching value, use foreach
to loop over
every element, and call last
as soon as you find a match:
my($match, $found, $item); foreach $item (@array) { if ($criterion) { $match = $item; # must save $found = 1; last; } } if ($found) { ## do something with $match } else { ## unfound }
To find a matching index, use for
to loop a
variable over every array index, and call last
as
soon as you find a match:
my($i, $match_idx); for ($i = 0; $i < @array; $i++) { if ($criterion) { $match_idx = $i; # save the index last; } } if (defined $match_idx) { ## found in $array[$match_idx] } else { ## unfound }
Not having a built-in mechanism to do this, we must write our own
code to go through the list and test each element. We use
foreach
and for
and call
last
to ensure that we stop as soon as we find a
match. Before we use last
to stop looking, though,
we save the value or index.
A common mistake is to try to use grep
here. The
problem is that grep
always tests all elements and
finds all matches, so it’s inefficient if you only want the
first match.
We have to set $match
when we want the value of
the first matching element. We can’t just test
$item
at the end of the loop, because
foreach
automatically local
izes
the iterator variable and this prevents us from getting to its last
loop value after the loop ends. See Section 4.4.
Here’s an example. Assume that @employees
has a list of Employee objects, sorted in descending order by salary.
We wish to find out the highest paid engineer, who will be the first
engineer in the array. We only want to print the engineer’s
name, so we want the value, not the index.
foreach $employee (@employees) { if ( $employee->category() eq 'engineer' ) { $highest_engineer = $employee; last; } } print "Highest paid engineer is: ", $highest_engineer->name(), "\n";
When we’re searching and only want the index, we can save some
code by remembering that $i
will not be an
acceptable array index if we don’t find a match. This mainly
saves us code space, as not doing an assignment doesn’t really
win us much compared to the time we’ll have spent testing the
list elements. It’s more obscure, because it tests
if
($i
<
@ARRAY)
to check whether we found a match, instead
of the more obvious defined
test as in the
previous Solution.
for ($i = 0; $i < @ARRAY; $i++) { last if $criterion; } if ($i < @ARRAY) { ## found and $i is the index } else { ## not found }
Get Perl Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.