sub mesh (\@\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@) { my $max = -1; $max < $#$_ && ( $max = $#$_ ) foreach @_; map { my $ix = $_; map $_->[$ix],@_; } 0 .. $max; }
来自List::MoreUtils模块.我在我的一个应用程序中使用它,我碰巧看到源代码,这让我觉得我根本不知道perl!任何人都可以解释这个疯狂吗? :) 谢谢!
解决方法
这是一个更可读的版本 – 理想情况下,它应该是自明的
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,... 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]; } } ; }
这是一个评论的原始版本
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; }
这种方法中的一个不寻常的事情是function signature (prototype)
.
sub mesh (\@\@;\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@\@) {
由于@mob和@ikegami在评论中明智地指出,
… It instructs Perl to expect between 2 and 32 named arrays,and to pass them to the function (in @_) as array references. So if you call
mesh @a,@b,@c
,then@_
in mesh is set to(\@a,\@b,\@c)
rather than one “flat” list with all the individual elements of@a,and @c
(mob)
… They technically don’t need to be named,just dereferenced. e.g.@$ref
and@{[qw( foo bar )]}
work just as well as@a
. In other words,it has to start with@
(and not be a slice). (ikegami)
换句话说,以下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);
这样做就可以将单个数组(而不是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.