LINUX.ORG.RU

[perl] Как взять по очереди по одному элементу из нескольких массивов?

 


0

1

Есть несколько массивов

my @l1 = (11,12,13);
my @l2 = (21,22,23);
my @l3 = (31,32,33);

Хочу на выходе получить массивы элементов исходных массивов, взятых по одинаковым индексам, то есть:

my @result = ([11,21,31],
[12,22,32],
[13,23,33]);

Хотел по традиции лиспа сделать map(), да не сообразил, как. В итоге, сделал через цикл for.

Можно такое же сделать через map?

★★

Ответ на: комментарий от anonymous

Мы уже давно как уехали. Но знать шашечки в лицо - это есть хорошо. Что по делу-то?

bk_ ★★
() автор топика

map в перле, в отличие от лиспового, итерирует лишь по одному списку. Так что надо делать map по индексам:

@a=(1,2,3);
@b=(4,5,6);
@c = map { [$a[$_], $b[$_]] } 0..$#a; # Если указывать массивы непосредственно
@d = map {			     # Если использовать массив ссылок на массивы
    my $i=$_;
    [map $_->[$i], (\@a, \@b)]; # здесь можно добавлять массивы
} 0..$#a;			# $#a -- максимальный индекс
kim-roader ★★
()
Ответ на: комментарий от tailgunner

map(list, zip(a1, a2, a3))

С каких пор в пятом перле существует zip? Да ещё от трёх аргументов? И почему мой perldoc про него не слышал?

P.S. Посмотреть как можно реализовать zip можно тут: http://stackoverflow.com/questions/38345/is-there-an-elegant-zip-to-interleav...

kim-roader ★★
()
Ответ на: комментарий от kim-roader

С каких пор в пятом перле существует zip?

В этом вашем перле даже zip нету? O_o

tailgunner ★★★★★
()
sub min {
 my $result = shift;
 foreach (@_) {
  $result = $_ if $_ < $result;
 };
 return $result;
};

sub mapnil(&@) {
 my ($function, @arrays) = @_;
 return if !@arrays || !$arrays[0];
 my $len = @{$arrays[0]};
 $len = min($len, scalar @$_) foreach @arrays;
 for (my $i = 0; $i < $len; ++$i) {
  $function->(map { $_->[$i] } @arrays);
 };
};

sub mapcar(&@) {
 my ($function, @arrays) = @_;
 my @result;
 mapnil { push @result, $function->(@_) } @arrays;
 return \@result;
};

my @l1 = (11,12,13);
my @l2 = (21,22,23);
my @l3 = (31,32,33);

$result = mapcar { \@_ } \@l1, \@l2, \@l3;

У меня уже целая библиотека лиспоподобных функций накопилась.

anonymous
()
Ответ на: комментарий от anonymous

За код спасибо, но производительность у него ужасная:

use strict;
use Data::Dumper;

my @l1 = (11, 12, 13);
my @l2 = (21, 22, 23);
my @l3 = (31, 32, 33);

sub v1 {
        my @result = ();
        for (my $i = 0; $i < 3; $i++) {
                $result[$i] = [$l1[$i], $l2[$i], $l3[$i]];
        }
#       print Dumper(@result);
}

sub v2 {
        my @result = map {
                [$l1[$_], $l2[$_], $l3[$_]]
        } 0..2;
#       print Dumper(@result);
}


sub min {
 my $result = shift;
 foreach (@_) {
  $result = $_ if $_ < $result;
 };
 return $result;
};

sub mapnil(&@) {
 my ($function, @arrays) = @_;
 return if !@arrays || !$arrays[0];
 my $len = @{$arrays[0]};
 $len = min($len, scalar @$_) foreach @arrays;
 for (my $i = 0; $i < $len; ++$i) {
  $function->(map { $_->[$i] } @arrays);
 };
};

sub mapcar(&@) {
 my ($function, @arrays) = @_;
 my @result;
 mapnil { push @result, $function->(@_) } @arrays;
return \@result;

};

sub v3 {
        mapcar { \@_ } \@l1, \@l2, \@l3;
}

for (my $i = 0; $i < 1000000; $i++) {
v1;
#v2
        #v3;
}
## v1
$ time perl a.pl

real	0m2.764s
user	0m2.751s
sys	0m0.005s
## v2
$ time perl a.pl

real	0m2.744s
user	0m2.736s
sys	0m0.006s
## v3
$ time perl a.pl

real	0m16.839s
user	0m16.793s
sys	0m0.012s
bk_ ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.