in reply to [untitled node, ID 160640]

This is covered in perlfaq4 where a foreach loop is a method used for a single test. You could also use grep in scalar context but thats a bad idea. To see why look at the faq_monk node found here. Perlfaq4 also mentions why using grep may be a bad idea.
  • Comment on Re: Checking for value in an array (without FOR)

Replies are listed 'Best First'.
Re: Re: Checking for value in an array (without FOR)
by Fletch (Bishop) on Apr 19, 2002 at 19:42 UTC

    That faq is somewhat out of date, as recent perls have been optimized such that map and grep don't build return lists if they're not required. As the benchmarking code below shows (numbers generated with 5.6.1 on a 1.2G Athlon):

    #!/usr/bin/perl use Benchmark qw( timethese cmpthese ); my @args = ( 100_000, { void => sub { grep { $_ == 50 } 0..100; 1 }, scalar => sub { my $res = grep { $_ == 50 } 0..100 }, list => sub { my @res = grep { $_ == 50 } 0..100 }, a_foreach => sub { my $match; foreach( 0..100 ) { $match++ if $_ == 50 } $match } } ); cmpthese( @args ); exit 0; __END__
    Benchmark: timing 100000 iterations of a_foreach, list, scalar, void...
     a_foreach:  4 wallclock secs ( 4.52 usr +  0.01 sys =  4.53 CPU) @ 22075.06/s (n=100000)
          list:  4 wallclock secs ( 3.35 usr +  0.00 sys =  3.35 CPU) @ 29850.75/s (n=100000)
        scalar:  3 wallclock secs ( 3.34 usr +  0.00 sys =  3.34 CPU) @ 29940.12/s (n=100000)
          void:  4 wallclock secs ( 3.29 usr +  0.00 sys =  3.29 CPU) @ 30395.14/s (n=100000)
                 Rate a_foreach      list    scalar      void
    a_foreach 22075/s        --      -26%      -26%      -27%
    list      29851/s       35%        --       -0%       -2%
    scalar    29940/s       36%        0%        --       -1%
    void      30395/s       38%        2%        2%        --
    

    There's practically no difference between grep in scalar and list context, while a foreach loop runs 26% slower.

    Update: Oops, I'd said foreach was 35% slower. Changed the last paragraph above.

    Update: Playing around, if you use grep EXPR, LIST rather than grep BLOCK LIST (i.e. grep $_ == 50, 0..100), that gap grows to 33% (since there's not as much overhead entering and leaving the block). If you switch comparisons from $_ == 50 to /50/ and stick with the BLOCK form, the foreach form is 45% faster.

      a_foreach could be faster, as it is in perlfaq4.

        Meaning:

        a_short_circuit_foreach => sub { my $present; foreach( 0..100 ) { if( /0/ ) { $present++; last } } $present },

        Which will best case (looking for the first item) be very much faster indeed (1178% than scalar grep), worst case just as bad as the non-short-circuit foreach, and "average" case (in the middle of the list) 12% faster. (All numbers are for the data in question for this benchmark, not in general).

        Of course if you're really serious about performance, just use a hash.

        #!/usr/bin/perl use Benchmark qw( timethese cmpthese ); my @data = ( 0 .. 100 ); my %cheat; @cheat{ @data } = (1) x @data; my @args = ( -1, { void => sub { grep /50/, @data; 1 }, scalar => sub { my $res = grep /50/, @data }, list => sub { my @res = grep /50/, @data }, a_foreach => sub { my $match; foreach( @data ) { $match++ if /50/ } $match }, a_short_circuit_foreach => sub { my $present; foreach( @data ) { if( /50/ ) { $present++; last } } $present; }, a_hash => sub { exists $cheat{ 50 }; } } ); cmpthese( @args ); exit 0; __END__
        
        Benchmark: running a_foreach, a_hash, a_short_circuit_foreach, list, scalar, void, each for at least 1 CPU seconds...
         a_foreach:  1 wallclock secs ( 1.06 usr +  0.00 sys =  1.06 CPU) @ 20286.79/s (n=21504)
            a_hash:  1 wallclock secs ( 1.11 usr +  0.01 sys =  1.12 CPU) @ 7080227.68/s (n=7929855)
        a_short_circuit_foreach:  2 wallclock secs ( 1.07 usr +  0.00 sys =  1.07 CPU) @ 40193.46/s (n=43007)
              list:  1 wallclock secs ( 1.04 usr +  0.00 sys =  1.04 CPU) @ 25845.19/s (n=26879)
            scalar:  1 wallclock secs ( 1.02 usr +  0.00 sys =  1.02 CPU) @ 26351.96/s (n=26879)
              void:  2 wallclock secs ( 1.04 usr +  0.00 sys =  1.04 CPU) @ 25845.19/s (n=26879)
                                     Rate a_foreach   void   list scalar a_short_circuit_foreach a_hash
        a_foreach                 20287/s        --   -22%   -22%   -23%                    -50%  -100%
        void                      25845/s       27%     --     0%    -2%                    -36%  -100%
        list                      25845/s       27%     0%     --    -2%                    -36%  -100%
        scalar                    26352/s       30%     2%     2%     --                    -34%  -100%
        a_short_circuit_foreach   40193/s       98%    56%    56%    53%                      --   -99%
        a_hash                  7080228/s    34801% 27295% 27295% 26768%                  17515%     --