для с несколькими массивами - PullRequest
8 голосов
/ 10 июня 2011

В Scheme вы можете перебирать несколько списков с помощью for-each:

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

Я знаю, что в Perl вы можете использовать for для перебора одного списка.Как можно перебрать несколько списков, как в примере со схемой?

Меня интересуют ответы на Perl 5 или 6.

Ответы [ 8 ]

10 голосов
/ 10 июня 2011

В Perl 6 Zip-оператор - лучший выбор.Если вы хотите получить оба значения (а не вычислять сумму напрямую), вы можете использовать ее без знака плюс:

for (10, 11, 12) Z (1, 2, 3) -> $a, $b {
    say "$a and $b";
}
9 голосов
/ 10 июня 2011

В Perl 5 вы можете использовать модуль List :: MoreUtils . Либо с попарно, либо с итератором, возвращаемым each_array (который может проходить более двух массивов для параллельного перебора).

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]";
}
6 голосов
/ 10 июня 2011

С помощью оператора Zip вы можете добиться того, что делаете с помощью схемы:

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

См. http://perlcabal.org/syn/S03.html#Zip_operators

2 голосов
/ 10 июня 2011

Algorithm :: Loops предлагает функцию MapCar для перебора нескольких массивов (с вариантами, которые по-разному работают с массивами неравного размера).

2 голосов
/ 10 июня 2011

Вы можете просто перебрать индексы массивов, если вы уверены, что они одного размера:

foreach( 0 .. $#array1 ) {
  print $array1[$_] + $array2[$_], "\n";
}
1 голос
/ 16 июня 2011

Поскольку вопрос так же прост, как простое добавление (/ умножение, деление, ...), а массивы не являются массивами массивов, вы также можете использовать гипероператоры для своей задачи:

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

(конечно, это ответ Perl6)

если у вас нет доступа к французским кавычкам «», вы можете переписать его как

<1 2 3> <<+>> <10 20 30>
1 голос
/ 10 июня 2011

Один из способов:

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])

Использование each_arrayref из 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])

Спасибо Алексу за указание List::MoreUtils.

0 голосов
/ 10 июня 2011

Одно решение (есть из чего выбирать) может выглядеть так:

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);

Я чувствую, что вы спрашиваете о foreach, который может выглядеть следующим образом:

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

Но в этом случае все не так гладко.Что произойдет, если какой-либо массив будет короче?

...