Finding All Elements in an Array Matching Certain Criteria

Problem

From a list, you want only the elements that match certain criteria.

This notion of extracting a subset of a larger list is common. It's how you find all engineers in a list of employees, all users in the "staff " group, and all the filenames you're interested in.

Solution

Use grep to apply a condition to all elements in the list and return only those for which the condition was true:

@MATCHING = grep {
 TEST ($_)
}
@LIST;

Discussion

This could also be accomplished with a foreach loop:

@matching = (); foreach (@list) {
 push(@matching, $_) if TEST ($_);
}

The Perl grep function is shorthand for all that looping and mucking about. It's not really like the Unix grep command; it doesn't have options to return line numbers or to negate the test, and it isn't limited to regular-expression tests. For example, to filter out just the large numbers from an array or to find out which keys in a hash have very large values:

@bigs = grep {
 $_ > 1_000_000
}
@nums; @pigs = grep {
 $users{$_} > 1e7
}
keys %users;

Here's something that sets @matching to lines from the who command that start with "gnat ":

@matching = grep {
 /^gnat /
}
`who`;

Here's another example:

@engineers = grep {
 $_->position() eq 'Engineer'
}
@employees;

It extracts only those objects from the array @employees whose position() method returns the string Engineer.

You could have even more complex tests in a grep:

@secondary_assistance = grep {
 $_->income >= 26_000 && $_->income < 30_000
}
@applicants;

But at that point you may decide it would be more legible to write a proper loop instead.

See Also

The "For Loops," "Foreach Loops," and "Loop Control" sections of perlsyn (1) and of Perl Developing; the grep function in perlfunc (1) and of Perl Developing; your system's who (1) manpage, if it exists;