You can optimize the grep / map somewhat by memoizing the result of the first match. Unfortunately, the rest of the items in the array are still processed, but each item is not fully evaluated thanks to shortcut boolean logic.
$ perl -w -lane 'local($first); print join(" ","** ",' \
-e 'grep { $first=1 if !$first and /^[A-Z]+$/ } @F)'
no No .NO. -NO- n0 no
**
YES no
** YES
no YES NO
** YES
In this example, we want to grep each line of input (-n
) for the first word (-a
splits the line into words and saves in @F
) that matches the pattern of only upper-case letters. Without the memoization, we would get "NO" in the output of the final line.
If the array is very long, you will save some CPU cycles/time since the grep expression will only evaluate ! $first
, which will be true after the first match. The rest of the expression will not be evaluated.
For using with map
, you do need to be cautious when the input is a string that equates to 0
string. See here:
perl -w -lane 'local($first); print join(" ","** ",' -e 'map { $first=$_ if !$first and /^[A-Z0-9]+$/ } @F)'
0 NO
** 0 NO
(This is BAD!).
On the second item, perl interprets !$first
as !0
, even though the 0
was a string.
So, with map, to be on the safe side, use ! defined $first
.
perl -w -lane 'local($first); print join(" ","** ",' -e 'map { $first=$_ if !defined $first and /^[A-Z0-9]+$/ } @F)'
0 NO
** 0
(correct)