Подтвердить что ты не робот

Perl - встроенная функция для "застежки-молнии" вместе с двумя массивами?

Я хочу объединить два массива равной длины в один массив, взяв первый элемент из массива A, первый элемент из массива B; второй элемент из A, второй элемент из B и т.д. Следующая программа иллюстрирует алгоритм:

# file zipper.pl
use strict;
use warnings;
use 5.010;

my @keys   = qw/abel baker charlie dog easy fox/;
my @values = qw/a b c d e f/;

# ==> Is there a builtin function that is equivalent of zipper()? <==
#
my %hash = zipper( \@keys, \@values );

while ( my ( $k, $v ) = each %hash ) {
    say "$k=$v";
}

# zipper(): Take two equal-length arrays and merge them (one from A, one from B,
# another from A, another from B, etc.) into a single array.
#
sub zipper {
    my $k_ref = shift;
    my $v_ref = shift;
    die "Arrays must be equal length" if @$k_ref != @$v_ref;
    my $i = 0;
    return map { $k_ref->[ $i++ ], $_ } @$v_ref;
}

Выход

$ ./zipper.pl 
easy=e
dog=d
fox=f
charlie=c
baker=b
abel=a

Мне интересно, не упустил ли я встроенную функцию в Perl, которая сделает эквивалент zipper(). Он будет находиться в самом внутреннем цикле программы и должен работать как можно быстрее. Если нет встроенного модуля или модуля CPAN, может ли кто-нибудь улучшить мою реализацию?

4b9b3361

Ответ 1

Другие дали хорошие ответы на вопрос о mesh/zip вопроса, но если вы просто создаете хэш из массива ключей и один из значений, вы можете сделать это с недооцененным хэш-фрагмент.

#!/usr/bin/env perl

use strict;
use warnings;

my @keys   = qw/abel baker charlie dog easy fox/;
my @values = qw/a b c d e f/;

my %hash;
@hash{@keys} = @values;

use Data::Dumper;
print Dumper \%hash;

Добавление

Я подумал, почему можно выбрать один метод над другим. Я лично считаю, что реализация среза так же читаема, как и zip, но другие могут не согласиться. Если вы часто это делаете, вам может потребоваться скорость, и в этом случае форма среза будет быстрее.

#!/usr/bin/env perl

use strict;
use warnings;

use List::MoreUtils qw/zip/;
use Benchmark qw/cmpthese/;

my @keys   = qw/abel baker charlie dog easy fox/;
my @values = qw/a b c d e f/;

cmpthese( 100000, {
  zip => sub {
    my %hash = zip @keys, @values;
  },
  slice => sub {
    my %hash;
    @hash{@keys} = @values;
  },
});

результаты:

         Rate   zip slice
zip   51282/s    --  -34%
slice 78125/s   52%    --

Ответ 2

Поскольку вы предложили идею CPAN, List::MoreUtils и zip.

use List::MoreUtils qw(zip);

my @keys   = qw/abel baker charlie dog easy fox/;
my @values = qw/a b c d e f/;

my @zipped = zip @keys, @values;

Содержимое @zipped будет:

abel, a, baker, b, charlie, c, dog, d, easy, e, fox, f

Хорошая часть использования этого метода - вы можете заархивировать более двух списков, если хотите. Поскольку Perl не имеет понятия типа кортежа, он почти похож на операцию сглаживания.

Ответ 3

Хотя эта специфическая функция уже существует в List:: MoreUtils, вы можете использовать прототипы, чтобы дать вашим собственным функциям массива внешний вид встроенных операторов массива (например, push, shift, pop):

sub zipper (++) {  # perldoc perlsub
  my ($k, $v) = @_;
  die "Arrays must be equal length" if @$k != @$v;
  my $i;
  return map { $k->[$i++], $_ } @$v
}

%hash = zipper @keys, @values;
%hash = zipper \@keys, \@values;
%hash = zipper $key_aref, $value_aref;