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

Folks I have a sample code that users a small array

app , Oracle , EPDMCA , Oracle , EPZXC

While I can find the Element Oracle What I need to do is to shift to the next Element and print this out instead

print out EPDMCA

print out EPZXC

my @array = ('app', 'Oracle', 'EPDMCA', 'Oracle' ,'EPZXC'); foreach my $element ( @array ) { if ($element eq "Oracle") { print "$element found\n"; # However what I realy need is the next Element after Oracle # e.g # EPDMCA # EPZXC } }

Can any kind Monk help.

Replies are listed 'Best First'.
Re: Find Element of array but use the next Element
by davido (Cardinal) on Jun 14, 2012 at 16:01 UTC

    List::MoreUtils is fun.

    use List::MoreUtils qw( indexes ); my @array = qw( app Oracle EPDMCA Oracle EPZXC ); defined $array[$_+1] && print "$array[$_+1]\n" for indexes { $_ eq 'Oracle' } @array;

    Updated: Allowed for the possibility of 'Oracle' appearing in an 'even' numbered element. At first it seemed like a given that it appears in 'odd' elements, but that's never stated in the question, so it's safer to assume it could appear anywhere in the array. Also allowed for the possibility that there is no element following an instance of 'Oracle'.

    Here's a similar approach with grep (eliminating the dependency on List::MoreUtils):

    my @array = qw( app Oracle EPDMCA Oracle EPZXC ); print "$array[$_]\n" for grep { $_>0 && $array[$_-1] eq 'Oracle' } 0 .. $#array;

    Just for the fun of it, a couple more:

    print "$array[$_]\n" for indexes { state $prev = ''; my $compare = $prev; $prev = $_; $compare eq 'Oracle'; } @array;
    print "$_\n" for grep { state $ix = -1; my $cmp_idx = $ix++; $cmp_idx >=0 && $array[$cmp_idx] eq 'Oracle'; } @array;

    Personally, I think the first 'index' implementation reads the cleanest because it explicitly tells the reader that the output is indices. The first 'grep' solution is a close second, since it eliminates the need for the defined test.

    Of course there's also the simple approach:

    my @array = qw( app Oracle EPDMCA Oracle EPZXC ); my $ix = 0; while( $ix < $#array ) { print $array[$ix+1] if $array[ix] eq 'Oracle'; $ix++; }

    It's hard to beat the good old fashioned while loop.


    Dave

Re: Find Element of array but use the next Element
by johngg (Canon) on Jun 14, 2012 at 17:05 UTC

    Similar to one of davido's but going to one short of the end of the array as there can't be anything after "Oracle" if "Oracle" is the last element.

    $ perl -E ' > @arr = qw{ app Oracle EPDMCA Oracle EPZXC Oracle }; > say $arr[ $_ + 1 ] for > grep { $arr[ $_ ] eq q{Oracle} } 0 .. $#arr - 1;' EPDMCA EPZXC $

    Cheers,

    JohnGG

Re: Find Element of array but use the next Element
by blue_cowdawg (Monsignor) on Jun 14, 2012 at 15:49 UTC
        While I can find the Element Oracle What I need to do is to shift to the next Element and print this out instead

    try this:

    my @array = ('app', 'Oracle', 'EPDMCA', 'Oracle' ,'EPZXC'); my $found=""; while(my $element=shift @array){ if ( $element eq 'Oracle' ) { $found=shift @array; last; } } printf "%s\n",$found;


    Peter L. Berghold -- Unix Professional
    Peter -at- Berghold -dot- Net; AOL IM redcowdawg Yahoo IM: blue_cowdawg
Re: Find Element of array but use the next Element
by Anonymous Monk on Jun 14, 2012 at 15:47 UTC
    See perlintro, use
    for my $ix ( 0 .. $#array ) { if( ... ){ print $array[ $ix + 1 ];
Re: Find Element of array but use the next Element
by dsheroh (Monsignor) on Jun 14, 2012 at 20:37 UTC
    Just for the sake of Another Way To Do It, here's one that doesn't have to look at array indexes:
    #!/usr/bin/env perl use strict; use warnings; my @array = qw( app Oracle EPDMCA Oracle EPZXC ); my $show_next; for my $element (@array) { print "$element found\n" if $show_next; $show_next = ($element eq 'Oracle'); }

      Folks thanks for all the replies.

      Some of them made sence other's I got a bit lost in index's

      In the end I went for the reply by dsheroh as I could easly use the answer in my code which now produces the right answer for me and save me having to go through 500 lines of excel sheet and split up the Oracle output

Re: Find Element of array but use the next Element
by NetWallah (Canon) on Jun 14, 2012 at 21:33 UTC
    Yet another way, using "reverse" and a faked-out "slice":
    >perl -e "@arr = qw{ app Oracle EPDMCA Oracle EPZXC Oracle }; print (map {$_ eq 'Oracle'? ($x):($x=$_)[2]} reverse @arr)"

                 I hope life isn't a big joke, because I don't get it.
                       -SNL

      Not getting it. Care to explain?
        Analyzing
        map {$_ eq 'Oracle'? ($x):($x=$_)[2]} reverse @arr
        Ok - reading backwards, the first thing that happens, is @arr gets "reversed".

        Next we process each element of the reversed array. If 'Oracle' is found, we return "$x". You way well ask - what is $x, and where did it get a value?

        That happens if $_ does NOT match. In that case, what happens is:
        * $x gets assigned the current element
        * a temporary LIST is generated because of the () - this contains ($x)
        * We index index into the second element ($x)[2] which does not exist
        *resulting in an EMPTY list
        *That gets sent to "map" which ignores that.

        SO - the only elements that "map" returns is the $x value when the current element is 'Oracle'. In this case, $x contains the value of the previous element, and because we are 'reversed', in real life, it contains the 'next' element.

        There is a potential complaint that the order of the returned values is reversed.
        This is easily fixed by throwing a 'reverse' in front of the 'map'.

                     I hope life isn't a big joke, because I don't get it.
                           -SNL

Re: Find Element of array but use the next Element
by morgon (Priest) on Jun 15, 2012 at 15:24 UTC
    I prefer "functional" solutions without an explicit loop:
    my @array = ('app', 'Oracle', 'EPDMCA', 'Oracle' ,'EPZXC'); my @ora_succs = map { $array[$_+1] } grep { $array[$_] eq "Oracle" } 0 +..$#array;
    Note that your problem is not clearly defined as you would need to specify the desired behaviour in the cases where "Oracle" is the last element or where an "Oracle" is followed by another "Oracle".
      Brilliant!. Simple ! Direct !. No Kludge. Love it.

      Now - why didn't I come up with that.

                   I hope life isn't a big joke, because I don't get it.
                         -SNL

Re: Find Element of array but use the next Element
by packetstormer (Monk) on Jun 15, 2012 at 07:42 UTC
    If you are using 5.12 you can use this:
    #!/usr/bin/perl use strict; use warnings; my @arr = ('app', 'Oracle', 'EPDMCA', 'Oracle' ,'EPZXC'); while (my($index,$value) = each @arr ) { if($value eq "Oracle") { print "Value next to Oracle is:$arr[$index+1]\n" } }

      ... with the little problem that it does not like Oracle as last Element of @arr:

      my @arr = ('app', 'Oracle', 'EPDMCA', 'Oracle' ,'EPZXC','Oracle');
      Value next to Oracle is:EPDMCA Value next to Oracle is:EPZXC Use of uninitialized value within @arr in concatenation (.) or string +at 976380.pl line 11. Value next to Oracle is:

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)