http://www.perlmonks.org?node_id=576909

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

I'm almost embarassed to ask this because Im sure the answer is no, but is it possible to have a foreach loop loop through and array and return 2 values of the array in the same call.

I'll try to explain it better,

@names = ('rita', 'sue','bob', 'daisy') foreach $name (@names){ print "$name xxxxx \n"; }
the xxxx would be some code that makes this function return
rita sue sue bob bob daisy daisy

If not, what is the best way of doing this? Im leaning towards using a forloop and the array in a scalar context.

Replies are listed 'Best First'.
Re: foreach loops
by Arunbear (Prior) on Oct 07, 2006 at 22:30 UTC
    Here is one way:
    use strict; my @names = ('rita', 'sue','bob', 'daisy'); $, = ' '; $\ = "\n"; foreach (0 .. $#names) { print @names[$_, $_+1]; }
    Output:
    rita sue sue bob bob daisy daisy
      If warnings are switched on you will get an 'Use of uninitialized value ...' message once you get to the last time around the loop as print tries to access one more element than is in the array. This stops the warning.

      use strict; use warnings; my @names = qw{rita sue bob daisy}; $, = q{ }; $\ = qq{\n}; foreach (0 .. $#names) { print $_ == $#names ? $names[$_] : @names[$_, $_ + 1]; }

      Cheers,

      JohnGG

        Thank you everyone. I think I've strayed into the relms of perl magic. What are these operators called? I'd like to find out more about them

        $,

        $\

Re: foreach loops
by Corion (Patriarch) on Oct 07, 2006 at 21:58 UTC

    foreach doesn't do that, but List::MoreUtils has the natatime (n-at-a-time) function, which does what you want:

    #!/opt/perl/bin/perl -w use strict; use List::MoreUtils qw(natatime); my @names = qw( a b c d e f ); my $it = natatime( 2, @names ); while (my @items = $it->()) { print "@items\n"; };

    Update: My answer is wrong - you want to process two items in the list, but reprocess items - Arunbear's solution below is what you want then. I didn't read your wanted output closely enough, sorry.

Re: foreach loops
by shenme (Priest) on Oct 07, 2006 at 21:57 UTC
    Check out List::MoreUtils natatime() as one way to do it.
Re: foreach loops
by zentara (Archbishop) on Oct 08, 2006 at 13:00 UTC
    Just for the sake of fun, if you switch to a while loop
    #!/usr/bin/perl use warnings; use strict; my @names = ('rita', 'sue','bob', 'daisy'); while (@names){ my $name1 = shift @names; my $name2 = shift @names; if( defined $name2){ print "$name1 $name2\n"; unshift @names, $name2; }else{ print "$name1\n";} }

    Output:

    rita sue sue bob bob daisy daisy

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
Re: foreach loops
by dokkeldepper (Friar) on Oct 08, 2006 at 10:38 UTC

    A very elegant and general solution: use Algorithm::Combinatorics qw/.../;

    For example:

    use Algorithm::Combinatorics qw/combinations/; @names = ('rita', 'sue','bob', 'daisy'); my $r=combinations(\@names,2); while(my $res=$r->next){ print "@$res\n"; }

    There are several other combinatorical functions to replace all these foreach loops...

Re: foreach loops
by pbeckingham (Parson) on Oct 08, 2006 at 13:19 UTC

    I think a C-style for loop would be appropriate here:

    my @names = ('rita', 'sue','bob', 'daisy'); for (my $i = 0; $i < @names; ++$i) { print $names[$i], ' ', ($names[$i+1] || ''), "\n"; }
    Output:
    rita sue sue bob bob daisy daisy



    pbeckingham - typist, perishable vertebrate.
Re: foreach loops
by jwkrahn (Abbot) on Oct 09, 2006 at 00:15 UTC
    Just to add One More Way To Do It:
    $ perl -we' my $names = join " ", ( "rita", "sue", "bob", "daisy" ); while ( $names =~ /(\S+)(?=\s*(\S*))/g ) { print "$1\t$2\n"; } ' rita sue sue bob bob daisy daisy