Perl - 内置函数将两个数组"拉链"在一起?

Cha*_*hap 18 arrays perl merge

我想通过从数组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;
}
Run Code Online (Sandbox Code Playgroud)

产量

$ ./zipper.pl 
easy=e
dog=d
fox=f
charlie=c
baker=b
abel=a
Run Code Online (Sandbox Code Playgroud)

我想知道我是否忽略了Perl中的内置函数,它将完全相当于zipper().它将位于程序的最内层循环中,并且需要尽可能快地运行.如果没有内置或CPAN模块,任何人都可以改进我的实现吗?

Joe*_*ger 25

其他人已经为问题的网格/拉链方面给出了很好的答案,但是如果你只是从一组键和一个值创建一个哈希值,你可以使用不太重要的哈希切片来完成它.

#!/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;
Run Code Online (Sandbox Code Playgroud)

附录

我开始思考为什么人们可以选择一种方法而不是另一种方法.我个人认为切片实现与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;
  },
});
Run Code Online (Sandbox Code Playgroud)

结果:

         Rate   zip slice
zip   51282/s    --  -34%
slice 78125/s   52%    --
Run Code Online (Sandbox Code Playgroud)


squ*_*guy 11

既然你提供了一个CPAN的想法,有List::MoreUtilszip.

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;
Run Code Online (Sandbox Code Playgroud)

内容@zipped将是:

abel, a, baker, b, charlie, c, dog, d, easy, e, fox, f
Run Code Online (Sandbox Code Playgroud)

关于使用此方法的好处是,如果您愿意,可以压缩两个以上的列表.由于Perl没有元组类型的概念,它几乎就像一个扁平化操作.


Jul*_*ren 5

虽然这个特定的功能列表:: 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;
Run Code Online (Sandbox Code Playgroud)

  • 关于原型的说明:我同意`+'比`\ @更可取,但前者仅在v14之后可用.`+`原型也接受任何标量,或者在呈现`@ array`或'%hash`变量时接受引用.在这里不使用它可能更干净. (2认同)