для с несколькими массивами

В схеме вы можете перебирать несколько списков с помощью 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.


person dharmatech    schedule 10.06.2011    source источник


Ответы (8)


В 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]";
}
person Alex    schedule 10.06.2011

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

for (10, 11, 12) Z (1, 2, 3) -> $a, $b {
    say "$a and $b";
}
person moritz    schedule 10.06.2011
comment
Спасибо, мортиз! См. Мой комментарий к ответу таджика. - person dharmatech; 10.06.2011

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

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

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

person tadzik    schedule 10.06.2011
comment
Спасибо таджик. Схема для каждого обобщается до 1 или более списков. Можно ли использовать zip для более чем двух списков? - person dharmatech; 10.06.2011
comment
Может, хотя в настоящее время Rakudo реализует это только для двух списков (известное ограничение). - person moritz; 10.06.2011

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

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

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

person ysth    schedule 10.06.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.

person dharmatech    schedule 10.06.2011

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

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

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

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

<1 2 3> <<+>> <10 20 30>
person Patrick J. S.    schedule 16.06.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;
}

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

person TLP    schedule 10.06.2011