Intro

In clpmisc, individual FAQ entries get regularly posted to the group: really, by our brian d foy. Specifically one that was recently posted (link @ GG) is How do I find the first array element for which a condition is true? to which some poster, "MrL22", replied:

# Do this using GREP my @people = ('Jacob Smith', 'Michael Brown', 'Joshua Smith', 'Matthew Cope'); @smiths = grep(/smith/i, @people);

Then of course several of us replied to the effect that

In particular, my followup said:

No! my $first = (grep /smith/i, @people)[0]; But inefficient, because it will grep more than necessary.

And here comes the pearl, which is Anno Siegel's further followup and which I'm reporting hereafter.

The Snippet

Here's the relevant part of Anno's post, with some formatting added:

I prefer to write that

my ( $first) = grep ...;

It can easily be combined with a check for uniqueness, which is sometimes an issue:

my @l = qw( foo bar baz); ( my ( $first) = grep /ba/ => @l ) > 1 and warn "not unique\n"; print "first: $first\n";

Now, I'm also repeating here what I've already written in the original thread: although the behaviour of list assignment in scalar context is well known to me, as is every single bit of syntax and semantics used here, I wouldn't have thought of that, and to do the same thing I would have probably concocted something more clumsy and not just as terse and readable. I suppose that many here are already familiar with the "technique", but I hope it will be of benefit to those that aren't.

BTW: we had recently had again in clpmisc a long, exhausting, often pitaful but in some corners interesting (sub-)thread (link @ GG) vastly dealing exactly with contexts, and lists, and list assignment.

Replies are listed 'Best First'.
Re: Cool example of list assignment usage
by perrin (Chancellor) on Jul 23, 2007 at 05:43 UTC
    ( my ( $first) = grep /ba/ => @l ) > 1 and warn "not unique\n";

    Okay, that is pretty confusing. Wouldn't you expect the outer parentheses to return $first in list context, rather than the number of matches from the grep? After looking at it closely for a couple of minutes, I can see why it works, but it sure doesn't scan quickly.

      Okay, that is pretty confusing. Wouldn't you expect the outer parentheses to return $first in list context, rather than the number of matches from the grep?

      No, I don't find it confusing at all, but maybe that's because while not claiming in any way to be a Perl guru or anything, fundamental bits and pieces of Perl semantics are deeply etched in my cortex. I don't expect the outer parens to return $first in list context because it's the same mechanism by virtue of which the (sometimes) so-called "goatse operator" (do not follow link if you don't already know and are easily impressed) =()= works. No NASA technology, just Perl: and then I find Perl semantics to be intuitive in most situations, with the exception of some corner cases, with the current one possibly falling in the latter category. But for some reasons it's still intuitive to me and, I believe, to most Perl programmers with a bare minimum of confidence with the language.

        I can't guess what =()= is supposed to do. Maybe this is similar to this regex construct, which I use even though it looks very non-intuitive to me:
        my ($match) = ($string =~ m/regex/);
Re: Cool example of list assignment usage
by ikegami (Patriarch) on Jul 23, 2007 at 19:43 UTC
    Very similarly, list assignment in scalar context is very useful for iterators.
    while (my ($value) = $iter->()) { ... }

    It allows the iterator to return false values without ending the loop.

      Very good example, ikegami, and one people may not think of that easily, as well.