Question

In Scheme you can iterate over multiple lists in with for-each:

> (for-each (lambda (a b) (display (+ a b)) (newline)) '(10 20 30) '(1 2 3))
11
22
33
> 

I know that in Perl you can use for to iterate over a single list. What's a good way to iterate over multiple lists as in the Scheme example?

I'm interested in answers for Perl 5 or 6.

Was it helpful?

Solution

In Perl 5 you can use the module List::MoreUtils. Either with pairwise or with the iterator returned by each_array (which can take more than two arrays to iterate through in parallel).

use 5.12.0;
use List::MoreUtils qw(pairwise each_array);

my @one = qw(a b c d e);
my @two = qw(q w e r t);

my @three = pairwise {"$a:$b"} @one, @two;

say join(" ", @three);

my $it = each_array(@one, @two);
while (my @elems = $it->()) {
    say "$elems[0] and $elems[1]";
}

OTHER TIPS

In Perl 6, the Zip operator is the nicest choice. If you want to get both values (and not compute the sum directly), you can use it without the plus sign:

for (10, 11, 12) Z (1, 2, 3) -> $a, $b {
    say "$a and $b";
}

With the Zip operator you can achieve what you're doing with Scheme:

> .say for (10, 20, 30) Z+ (1, 2, 3)
11
22
33

See http://perlcabal.org/syn/S03.html#Zip_operators

You could just iterate over the indices of the arrays, if you're sure they're the same size:

foreach( 0 .. $#array1 ) {
  print $array1[$_] + $array2[$_], "\n";
}

Algorithm::Loops offers a MapCar function for iterating over multiple arrays (with variants that deal differently with unequally sized arrays).

One way is:

sub for_each
{
    my $proc = shift ;

    my $len = @{$_[0]} ;

    for ( my $i = 0 ; $i < $len ; $i++ )
    {
        my @args = map $_->[$i] , @_ ;

        &$proc ( @args ) ;
    }
}

for_each sub { say $_[0] + $_[1] } , ([10,20,30],[1,2,3])

Using each_arrayref from List::MoreUtils:

sub for_each
{
    my $proc = shift ;

    my $it = each_arrayref ( @_ ) ;

    while ( my @elts = $it->() ) { &$proc ( @elts ) } ;
}

for_each sub { say $_[0] + $_[1] } , ([10,20,30],[1,2,3])

Thanks to Alex for pointing out List::MoreUtils.

As long as the question is as simple as just adding (/multiplying, dividing,…) and the Arrays are no Arrays of Arrays, you also could use the hyper-operators for your task:

<1 2 3> «+» <10 20 30>

(of course this is a Perl6 answer)

if you don't have access to the French quotes «», you could rewrite it as

<1 2 3> <<+>> <10 20 30>

One solution (there are many to choose from) might look like this:

my @argle = (10, 20, 30);
my @bargle = (1, 2, 3);
do {
    my $yin = shift @argle;
    my $yang = shift @bargle;
    say $yin + $yang;
} while (@argle && @bargle);

I sense that you are asking about foreach, which might look like this:

my @argle = (10, 20, 30);
my @bargle = (1, 2, 3);
for my $yin (@argle) {
    my $yang = shift @bargle;
    say $yin + $yang;
}

But it is not as smooth in this case. What happens if either array is shorter?

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top