#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
Комментарии:
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;
}
Но в этом случае все не так гладко. Что произойдет, если любой из массивов короче?