Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Dear experts,

I would like to get the element with odd index of an array, into another new array. I am wondering if one could get it with GREP quickly?

For example I have this array:
my @arr = (1,2,3,4,5,6); # # # # I would like to return $VAR = [2,4,6];
Another example
my @arr = (0,3,4,5,8,10,12,15); # # # # # I would like to return $VAR = [3,5,10,15];
Any suggestion for this?

Replies are listed 'Best First'.
Re: Quicly extracting odd index elements in the array with grep
by GrandFather (Saint) on Aug 10, 2006 at 04:23 UTC

    grep and map:

    use warnings; use strict; my @arr = (0,3,4,5,8,10,12,15); # # # # my @var = map {$arr[$_]} grep {$_ & 1} 1..$#arr; print "@var";

    Prints:

    3 5 10 15

    DWIM is Perl's answer to Gödel

      Here are some more efficient variants, if dealing with long lists. The first uses only half as much memory (and is probably faster), and the second uses no extra memory (and is probably the fastestand is still quite fast). The difference should be inconsequential for short lists.

      my @var = map { $arr[$_*2+1] } 0..int(@arr/2)-1;
      my @var; push(@var, $arr[$_*2+1]) for 0..int(@arr/2)-1;

      Update: For speed considerations when dealing with long lists, refer to GrandFather's post.

      You can eliminate the map by taking a slice:

      my @var = @arr[ grep {$_ & 1} 1..$#arr ];

      GrandFather

      can you explain me the following line. I am not able to understand what is that doing exactly.
      my @var = map {$arr$_} grep {$_ & 1} 1..$#arr;

        Read the comments from the bottom up.
        my @var = # Store the elements in @var. map { $arr[$_] } # Get the elements at the remaining indexes. grep { $_ & 1 } # Filter out the even indexes. 0..$#arr; # Create a list of @arr's indexes.
Re: Quicly extracting odd index elements in the array with grep
by tilly (Archbishop) on Aug 10, 2006 at 04:46 UTC
    grep only:
    my @arr = (1,2,3,4,5,6); my $ind = 0; my @result = grep {$ind++ % 2} @arr;

      and it's faster for not having to generate an extra array:

      use warnings; use strict; use Benchmark qw(cmpthese); my @arr = (0,3,4,5,8,10,12,15, 1..999999); cmpthese (-2, { mapgrep => sub {map {$arr[$_]} grep {$_ & 1} 1..$#arr}, slice => sub {@arr[ grep {$_ & 1} 1..$#arr ];}, grep => sub {my $ind = 0; grep {$ind++ % 2} @arr}, push => sub {my @var; push(@var, $arr[$_*2+1]) for 0..int(@arr +/2)-1}, map => sub {map { $arr[$_*2+1] } 0..int(@arr/2)-1}, } );

      Prints:

      # my @arr = (0,3,4,5,8,10,12,15, 1..999999); Rate mapgrep slice push map grep mapgrep 2.02/s -- -29% -35% -38% -40% slice 2.84/s 40% -- -9% -13% -16% push 3.11/s 54% 9% -- -5% -8% map 3.27/s 62% 15% 5% -- -3% grep 3.37/s 66% 18% 8% 3% -- # my @arr = (0,3,4,5,8,10,12,15); Rate push mapgrep slice map grep push 160309/s -- -30% -39% -50% -54% mapgrep 229948/s 43% -- -12% -28% -34% slice 261705/s 63% 14% -- -18% -25% map 319334/s 99% 39% 22% -- -9% grep 350258/s 118% 52% 34% 10% --

      The performance holds pretty much regardless of size.

      Update: more cases added


      DWIM is Perl's answer to Gödel

        I was curious how using map and multiplication to generate the slice, without any conditionals, would compare. ("mult" in this example.) Interestingly, map is killing grep on my machine, which differs from what GrandFather got.

        #/usr/bin/perl use warnings; use strict; use Benchmark qw(cmpthese); my @arr = (0,3,4,5,8,10,12,15, 1..999999); cmpthese (-2, { mapgrep => sub {map {$arr[$_]} grep {$_ & 1} 1..$#arr}, slice => sub {@arr[ grep {$_ & 1} 1..$#arr ];}, mult => sub {@arr[map {$_*2+1} 0..int(@arr/2)-1];}, grep => sub {my $ind = 0; grep {$ind++ % 2} @arr}, push => sub {my @var; push(@var, $arr[$_*2+1]) for 0..int(@arr +/2)-1}, map => sub {map { $arr[$_*2+1] } 0..int(@arr/2)-1}, } );

        This is a multiprocessor x86-64 machine, for what it's worth.

        ~/perl$ cat /proc/version Linux version 2.6.26.8-57.fc8 (mockbuild@x86-4.fedora.phx.redhat.com) +(gcc version 4.1.2 20070925 (Red Hat 4.1.2-33)) #1 SMP Thu Dec 18 18: +59:49 EST 2008 ~/perl$ perl -v This is perl, v5.8.8 built for x86_64-linux-thread-multi ~/perl$ perl ./everyother.pl Rate mapgrep slice push mult grep map mapgrep 5.24/s -- -22% -28% -33% -34% -43% slice 6.73/s 28% -- -8% -14% -15% -27% push 7.28/s 39% 8% -- -7% -8% -21% mult 7.80/s 49% 16% 7% -- -1% -15% grep 7.92/s 51% 18% 9% 1% -- -14% map 9.22/s 76% 37% 27% 18% 16% --

        Update: As an added note, ($_<<1)+1 is slightly faster still, but doesn't catch up to the map and grep solutions.

      How can I modify your code above, if given:
      my @arr = (0,1,2,3,4,5,6,8,10); # # # # Giving $VAR = [1,4,8];
      Namely, keep index-1 and then get index at interval 3 subsequently.
        my @arr = (0,1,2,3,4,5,6,8,10); my $ind = 0; my @result = grep {1 == $ind++ % 3} @arr;
Re: Quicly extracting odd index elements in the array with grep
by jwkrahn (Abbot) on Aug 10, 2006 at 07:22 UTC
    my @arr = (0,3,4,5,8,10,12,15); my @new = do { local $| = 1; grep --$|, @arr };