для работы с несколькими массивами

#perl #raku

#perl #raku

Вопрос:

В 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.

Ответ №1:

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

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

Комментарии:

1. Спасибо, мортиз! Смотрите мой комментарий к ответу тадзика.

Ответ №2:

В Perl 5 вы можете использовать модуль List::MoreUtils. Либо с помощью pairwise, либо с помощью итератора, возвращаемого 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]";
}
  

Ответ №3:

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

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

Смотрите http://perlcabal.org/syn/S03.html#Zip_operators

Комментарии:

1. Спасибо, тадзик. Схема for-each обобщается на 1 или более списков. Можно ли использовать zip для более чем двух списков?

2. Это возможно, хотя Rakudo в настоящее время реализует это только для двух списков (известное ограничение).

Ответ №4:

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

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

Ответ №5:

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

Ответ №6:

Одним из способов является:

 sub for_each
{
    my $proc = shift ;

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

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

        amp;$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->() ) { amp;$proc ( @elts ) } ;
}

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

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

Ответ №7:

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

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

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

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

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

Ответ №8:

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

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

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

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

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