Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

grep { $var } @arr

by igelkott (Priest)
on Jul 17, 2014 at 14:46 UTC ( #1094064=perlquestion: print w/replies, xml ) Need Help??
igelkott has asked for the wisdom of the Perl Monks concerning the following question:

Is it possible to use a variable in place of the expression or block of grep? Am I missing something simple or is this simply illegal?

With the simple fragment below, I would like to get a result of 1,2 for both greps but I get all elements on the second. Btw, I get the same results from the expression version: "grep $var, @arr".

use strict; use warnings; my @arr = (1, 2, 3, 4, 5); my $pat = '$_ < 3'; my @res; @res = grep {$_ < 3} @arr; print "Literal:\t@res\n"; @res = grep {$pat} @arr; print "Variable:\t@res\n";

Of course, this is just a test script. The real thing builds the grep pattern in several steps and searches a two-dimensional array. I could do all this differently but the most obvious alternative would be a long list of if statements.

Replies are listed 'Best First'.
Re: grep { $var } @arr
by Athanasius (Chancellor) on Jul 17, 2014 at 14:56 UTC

    Another option is to use a subroutine reference instead of a string:

    #! perl use strict; use warnings; my @arr = (1, 2, 3, 4, 5); my $pat = sub { $_[0] < 3 }; my @res; @res = grep {$_ < 3} @arr; print "Literal:\t@res\n"; @res = grep { $pat->($_) } @arr; print "Variable:\t@res\n";


    0:52 >perl Literal: 1 2 Variable: 1 2 0:52 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: grep { $var } @arr
by toolic (Bishop) on Jul 17, 2014 at 14:53 UTC
    eval seems to work (with the usual security disclaimers):
    @res = grep {eval $pat} @arr;
      eval $pat

      Thanks! I feel like a total fool but it's worth having such a simple fix.

      This works on my overly complex, multi-dimensional problem as well.

Re: grep { $var } @arr
by LanX (Bishop) on Jul 17, 2014 at 14:58 UTC
    > Am I missing something simple or is this simply illegal?

    Its code, so put it into a function. grep allows replacing the EXPR with a function call and $_ is global anyway. :)

    Cheers Rolf

    (addicted to the Perl Programming Language)

Re: grep { $var } @arr
by Anonymous Monk on Jul 17, 2014 at 14:58 UTC

    You are not using a pattern which, to me, implies m// or index() use; you are actually using a code block.

    Use a list of sub references to iterate over instead ...

    @test = ( sub { $_[0] < 3 } ); for my $t ( @test ) { print join q[ ] , grep $t->( $_ ), 1 .. 5; }
Re: grep { $var } @arr
by bulrush (Scribe) on Jul 17, 2014 at 16:53 UTC
    Yes you can do that but I usually do it like this:
    @res = grep (/$pat/g, @arr);
    Perl 5.8.8 on Redhat Linux RHEL 5.5.56 (64-bit)
      Well, bulrush, you did not say how you populate $pat, but I fail to see how a regex would figure out whether a value is larger or smaller than 3.

      I definitely agree that a subroutine reference is a very good solution, perhaps the best.

        I fail to see how a regex would figure out whether a value is larger or smaller than 3.

        You can get clever with match-time pattern interpolation. For instance:

        my @list = (1..5); my $pattern = qr/\d+(??{if($& < 3) { "" } else { "(?<!\\d)" } })/; my @res = grep /$pattern/, @list; say join ", ", @res;

        This also (ab)uses negative look-behind assertions to create a subpattern that is guaranteed to fail (in this regex, not in general).

        But I agree, subroutine references are the way to go here.


      Perhaps I've misunderstood but with my current $var, using /$pat/g will result in no matches (with or without the 'g' modifier). As far as I know, this will look for the literal string of '$_ < 3' on my array, as written below (appending to the initial script).

      @res = grep {/$pat/g} @arr; print "Search:\t@res\n";

      This finds none of the elements of @arr.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1094064]
Approved by toolic
[karlgoethebier]: Hi mario
[marioroy]: Hi karlgoethebier.
[karlgoethebier]: "Long time No See" ;-)
[marioroy]: Yes. I've been working on MCE and MCE::Shared. These are completed and released. MCE 1.830 and MCE::Shared 1.831. Saw the LWP::Simple and P::FM thread and thought to help out.
[marioroy]: Today, wanted to revisit running parallel Re: Crash with ForkManager on Windows. I tried running on Cygwin for comparison.

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (7)
As of 2017-09-23 15:56 GMT
Find Nodes?
    Voting Booth?
    During the recent solar eclipse, I:

    Results (272 votes). Check out past polls.