Как суммировать массивы по элементам в Perl?
у меня есть два массива:
@arr1 = ( 1, 0, 0, 0, 1 );
@arr2 = ( 1, 1, 0, 1, 1 );
Я хочу суммировать элементы обоих массивов, чтобы получить новый, как
( 2, 1, 0, 1, 2 );
могу ли я сделать это без цикла через массивы?
9 ответов
Если вы используете Perl 6:
@a = (1 0 0 0 1) <<+>> (1 1 0 1 1) #NB: the arrays need to be the same size
на Perl 6 Адвент Календарь больше примеров.
принципиально, нет, вы не можете сделать это без "цикла через массивы", потому что вам нужно получить доступ к каждому элементу обоих массивов, чтобы суммировать их. Оба ответа до сих пор просто скрывают цикл под слоем абстракции, но он все еще там.
Если вас беспокоит цикл по очень большим массивам, вероятно, лучше рассмотреть другие способы сохранения суммы в актуальном состоянии.
что плохого в зацикливании на массивах? это основные принципы.
@arr1 = ( 1, 0, 0, 0, 1 );
@arr2 = ( 1, 1, 0, 1, 1 );
for ($i=0;$i<scalar @arr1;$i++){
print $arr[$i] + $arr2[$i] ."\n";
}
вы видели стиль C для цикла, и pairwise
. Вот идиоматический Perl для цикла и map
:
my @arr1 = ( 1, 0, 0, 0, 1 );
my @arr2 = ( 1, 1, 0, 1, 1 );
my @for_loop;
for my $i ( 0..$#arr1 ) {
push @for_loop, $arr1[$i] + $arr2[$i];
}
my @map_array = map { $arr1[$_] + $arr2[$_] } 0..$#arr1;
мне нравится map
и pairwise
лучшие. Я не уверен, что у меня есть предпочтение между этими двумя вариантами. pairwise
обрабатывает некоторые скучные детали сантехники для вас, но это не встроенный как map
. С другой стороны, решение карту очень идиоматические и может быть непрозрачным, чтобы часть времени продажи.
Итак, никаких реальных побед для любого подхода. ИМО, оба pairwise
и map
хорошо.
Если вы действительно боитесь цикла, то вы можете двоично нарезать массивы, суммировать пары,а затем рекурсивно собрать полученный массив. Там нет цикла, и в качестве бонуса вы узнаете, как работает часть деривации быстрого преобразования Фурье.
от http://www.perlmonks.org/?node_id=122393
@a = qw(1 2 3 4);
@b = qw(1 2 3 4);
@c = ();
@c = map { $a[$_] + $b[$_] } ( 0 .. (@a > @b ? $#a : $#b) );
или:
$c[@c] = $a[@c] + $b[@c] while defined $a[@c] or defined $b[@c];
или:
$c[$_] = $a[$_] + $b[$_] for 0 .. (@a > @b ? $#a : $#b);
или (в Perl 6):
@c = @a ^+ @b
чтобы избежать (явного) цикла, вот решение, которое использует рекурсию "вместо":
#!/usr/bin/perl
use v5.20;
my @arr1 = ( 1, 0, 0, 0, 1 );
my @arr2 = ( 1, 1, 0, 1, 1 );
my @result=non_looping_pairwise_sum([ @arr1 ], [ @arr2 ]); # pass in copies, so the originals are not modified
say "@result";
sub non_looping_pairwise_sum { # only handles lists that have the same length
my ($a1, $a2)=@_;
return () if (scalar(@$a1)==0 and scalar(@$a2)==0);
my $e1=shift @$a1;
my $e2=shift @$a2;
return ($e1+$e2, non_looping_pairwise_sum($a1, $a2));
}
выход:
2 1 0 1 2
отметим, что use v5.20
означает, что вам не нужно писать use strict; use warnings
, Я думаю.
извинения / слава @parm за идею.
Я не уверен, что вы планируете делать с суммой, как только она у вас есть, но вы планируете делать больше вещей типа vector-y, а затем Math::Matrix может быть хорошим.
use Math::Matrix;
my $foo = Math::Matrix->new([ 1, 0, 0, 0, 1 ]);
my $bar = Math::Matrix->new([ 1, 1, 0, 1, 1 ]);
my $sum = $foo->add($bar);