Pretty simple, but I find it useful:
my @all = ('a', 'b', 'c', '1', '2', '3'); my ($numbers, $letters) = grep2 {/\d/} @all; print "numbers: @$numbers\n"; # prints "1 2 3" print "letters: @$letters\n"; # prints "a b c"
sub grep2 (&@) { my $code = shift; my $true = []; my $false = []; foreach (@_) { if (&{$code}()) { push @$true, $_; } else { push @$false, $_; } } return ($true, $false); } my @all = ('a', 'b', 'c', '1', '2', '3'); my ($numbers, $letters) = grep2 {/\d/} @all; print "numbers: @$numbers\n"; # prints "1 2 3" print "letters: @$letters\n"; # prints "a b c" print "all: @all\n";

Replies are listed 'Best First'.
Re: grep2 (like 'grep', but also return non-matches)
by ccn (Vicar) on Jan 14, 2005 at 18:30 UTC

    Nice one.

    The same but little bit more shortly:

    sub grep2 (&@) { my $code = shift; my ($true, $false) = ([], []); push @{ &{$code}() ? $true : $false }, $_ for @_; return ($true, $false); }
Re: grep2 (like 'grep', but also return non-matches)
by BrentDax (Hermit) on Jan 24, 2005 at 19:32 UTC

    You might be interested in my List::Part module, which basically does the same thing in a more general way.

    use List::Part; ($letters, $numbers)=part { /\d/ } qw(a b c 1 2 3);

    The main function of the module looks like this:

    sub part(&@) { my $code=shift; my @ret; for(@_) { my $i=$code->($_); next unless defined $i; push @{$ret[$i]}, $_; } return @ret; }

    =cut
    --Brent Dax
    There is no sig.

      Could I please ask that anyone who plays with $_ like this ... please localise it?

      sub part(&@) { my $code=shift; my @ret; local $_; for(@_) { my $i=$code->($_); next unless defined $i; push @{$ret[$i]}, $_; } return @ret; }

      Thanks. There are some really hard-to-figure-out bugs that creep up on people when the subs they call go and affect $_ like this.

      Tanktalus, twice bitten, once shy. Or something like that.

        perlsyn sez about foreach:

        ...the variable is implicitly local to the loop and regains its former value upon exiting the loop.

        So I think this is quite safe.

        =cut
        --Brent Dax
        There is no sig.

Re: grep2 (like 'grep', but also return non-matches)
by belg4mit (Prior) on Jan 16, 2005 at 15:05 UTC
    For short lists it probably makes more sense to just traverse the list twice, once with the the test negated... rather than dealing with references.

    --
    I'm not belgian but I play one on TV. On dit que je parle comme un belge aussi.