List :: MoreUtils网格或'zip'功能

src*_*ulo 12 perl perl-module

所以这个问题纯粹是出于学习目的和好奇心,但任何人都可以解释下面的功能是如何工作的?

sub mesh (\@\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@) {
    my $max = -1;
    $max < $#$_ && ( $max = $#$_ ) foreach @_;
    map {
        my $ix = $_;
        map $_->[$ix], @_;
    } 0 .. $max;
}
Run Code Online (Sandbox Code Playgroud)

它来自List :: MoreUtils模块.我在我的一个应用程序中使用它,我碰巧看到了源代码,这让我觉得我根本不懂perl!任何人都可以解释这种疯狂吗?:) 谢谢!

DVK*_*DVK 13

我不会覆盖原型部分(暴徒说他会).

这是一个更易阅读的版本 - 理想情况下,它应该是自我解释的

sub mesh (\@\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@) {

    # Calculate the maximum number of elements in each of the array refs 
    # we were passed:

    my $maxLength = 0;
    foreach my $array_ref (@_) { # @_ is all arrey refs passed in
        if ($maxLength < @$array_ref) { 
            # we found an array longer than all previous ones 
            $maxLength = @$array_ref;
        }
    }

    # If you represent the arrays as a matrix:
    #   ARR1 = [ a1e1, a1e2, .... a1eN],
    #   ARR2 = [ a2e1, a2e2, .... a2eN],
    #    ...
    #   ARR2 = [ aMe1, aMe2, .... aMeN];
    # Then, we are simply walking through the matrix;
    # each column top to bottom then move on to next column left to right
    # (a1e1, a2e1, ... aMe1, a1e2, a2e2, ... aMeN)

    my @results;
    for (my $index = 0; $index < $maxLength; $index++) { # Iterate over columns
         foreach my $array_ref (@_) { # Iterate over per-row cells in each column
             push @results, $array_ref->[$index];
         }
    } ;
}
Run Code Online (Sandbox Code Playgroud)

这是一个评论的原始版本

sub mesh (\@\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@) {

    # Calculate the largest index in each of the array refs
    # @_ is an array of all the input arrayrefs
    # $_ will be one of the array refs in a foreach loop
    # $#{$X} is the largest index in arrayref X; thus
    # $#$_ is the largest index in arrayref $_
    my $max = -1;
    $max < $#$_ && ( $max = $#$_ ) foreach @_;

    # Return a list, obtained by looping 
    # over every index from 0 to the maximal index of any of the arrays
    # Then, for each value of the index ($ix), push into the resulting list
    # an element with that index from each of the arrays.
    map {
        my $ix = $_;
        map $_->[$ix], @_;
    } 0 .. $max;
}
Run Code Online (Sandbox Code Playgroud)

这种方法中不寻常的一件事就是function signature (prototype).

sub mesh (\@\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@) {
Run Code Online (Sandbox Code Playgroud)

正如@mob和@ikegami在评论中明智地指出的那样,

...它指示Perl期望2到32个命名数组,并将它们作为数组引用传递给函数(在@_中).因此,如果你打电话mesh @a,@b,@c,那么@_在网格设置(\@a,\@b,\@c)而不是一个"平面"列表与@a, @b, and @c(暴徒)的所有单个元素
...他们在技术上不需要被命名,只是解除引用.例如@$ref@{[qw( foo bar )]}工作一样好@a.换句话说,它必须从@(而不是切片)开始.(池上)

换句话说,以下2个调用的行为相同

my @a1 = (1);
my @a2 = (2);
sub mesh_prototype(\@\@) { print "$_->[0]\n" }
sub mesh_pass_arrayref() { print "$_->[0]\n" }
mesh_prototype(@a1, @a2);
mesh_pass_arrayref(\@a1, \@a2);
Run Code Online (Sandbox Code Playgroud)

这样做是为了您可以将单个数组(而不是arrayrefs)作为参数传递给与内置函数类似的函数(例如map/ sort)

要回答Zaid关于如果将1或33个数组列为要调用的参数会发生什么的查询mesh(),它将生成编译时错误:

Not enough arguments for main::mesh at mesh.pl line 16, near "@a1)"
Execution of mesh.pl aborted due to compilation errors.

Too many arguments for main::mesh at mesh.pl line 16, near "@a2)"
Execution of mesh.pl aborted due to compilation errors.
Run Code Online (Sandbox Code Playgroud)

  • 我将介绍原型部分:-).它指示Perl期望2到32*个命名数组*,并将它们作为数组引用传递给函数(在`@ _`中).因此,如果你调用`mesh @ a,@ b,@ c`,```中的`@ _`被设置为`(\ @a,\ @ b,\ @ c)`而不是一个"平面"列表`@ a`,`@ b`和`@ c`的所有单个元素. (5认同)
  • @mob,他们在技术上不需要*命名*,只是*dereferenced*.例如`@ $ ref`和`@ {[qw(foo bar)]}`和`@ a`一样工作.换句话说,它必须从`@`开始(而不是切片). (2认同)