Some problems that may appear very complex are actually simple once you've seen a solution or two. For example, suppose you want to find the items in a list that have odd digit sums but don't want the items themselves. What you want to know is where they occurred in the original list.

All that's required is a bit of
indirection.^{[6]}

^{[6]}A famous computing maxim states that "there is no problem so complex that it cannot be solved with appropriate additional layers of indirection." Of course, with indirection comes obfuscation, so there's got to be a magic middle ground somewhere.

First, you have a selection
problem, so you use a `grep`. Let's
not `grep` the values themselves but the index for
each item:

my @input_numbers = (1, 2, 4, 8, 16, 32, 64); my @indices_of_odd_digit_sums = grep { ... } 0..$#input_numbers;

Here, the expression `0..$#input_numbers` will be a
list of indices for the array. Inside the block,
`$_` is a small integer, from 0 to 6 (seven items
total). Now, you don't want to decide whether
`$_` has an odd digit sum. You want to know whether
the array element at that index has an odd digit sum. Instead of
using `$_` to get the number of interest, use
`$input_numbers[$_]`:

my @indices_of_odd_digit_sums = grep { my $number = $input_numbers[$_]; my $sum; $sum += $_ for split //, $number; $sum % 2; } 0..$#input_numbers;

The result will be the indices at which 1, 16, and 32 appear in the list: 0, 4, and 5. You could use these indices in an array slice to get the original values again:

my @odd_digit_sums = @input_numbers[ @indices_of_odd_digit_sums ];

The strategy here for an indirect `grep` or
`map` is to think of the `$_`
values as identifying a particular item of interest, such as the key
in a hash or the index of an array, and then use that identification
within the block or expression to access the actual values.

Here's another example: select the elements of
`@x` that are larger than the corresponding value in
`@y`. Again, you'll use the indices
of `@x` as your `$_` items:

my @bigger_indices = grep { if ($_ > $#y or $x[$_] > $y[$_]) { 1; # yes, select it } else { 0; # no, don't select it } } 0..$#x; my @bigger = @x[@bigger_indices];

In the `grep`,
`$_` varies from 0 to the highest index of
`@x`. If that element is beyond the end of
`@y`, you automatically select it. Otherwise, you
look at the individual corresponding values of the two arrays,
selecting only the ones that meet your match.

However, this is a bit more verbose than it needs to be. You could simply return the boolean expression rather than a separate 1 or 0:

my @bigger_indices = grep { $_ > $#y or $x[$_] > $y[$_]; } 0..$#x; my @bigger = @x[@bigger_indices];

More easily, you can skip the step of
building the intermediate array by simply returning the items of
interest with a `map`:

my @bigger = map { if ($_ > $#y or $x[$_] > $y[$_]) { $x[$_]; } else { ( ); } } 0..$#x;

If the index is good, return the resulting array value. If the index is bad, return an empty list, making that item disappear.