18

配列 A の最初の要素と配列 B の最初の要素を取得して、同じ長さの 2 つの配列を 1 つの配列にマージしたいと考えています。A の 2 番目の要素、B の 2 番目の要素など。次のプログラムはアルゴリズムを示しています。

# 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

Zipper() に相当する Perl の組み込み関数を見落としていないかどうか疑問に思っています。これはプログラムの最も内側のループにあり、できるだけ速く実行する必要があります。組み込みモジュールまたは CPAN モジュールがない場合、誰かが私の実装を改善できますか?

4

4 に答える 4

25

質問のメッシュ/ジップ側について他の人が良い答えを出していますが、キーの配列と値の1つからハッシュを作成するだけの場合は、過小評価されているハッシュスライスでそれを行うことができます.

#!/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%    --
于 2013-05-26T03:12:20.423 に答える
5

この特定の関数は List::MoreUtils に既に存在しますが、プロトタイプを使用して、独自の配列関数に組み込みの配列演算子 ( pushshift、 など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;
于 2013-05-26T02:39:17.847 に答える