将两个或多个数组传递给 Perl 子例程
Posted
技术标签:
【中文标题】将两个或多个数组传递给 Perl 子例程【英文标题】:Passing two or more arrays to a Perl subroutine 【发布时间】:2011-08-06 12:19:18 【问题描述】:我在子例程中传递和读取参数时遇到问题,该子例程应该有两个数组。
sub two_array_sum # two_array_sum ( (1 2 3 4), (2, 4, 0, 1) ) -> (3, 6, 3, 5)
# I would like to use parameters @a and @b as simply as possible
# I would like to call two_array_sum here and pass two arrays, @c and @d
我从网上看到并尝试了几个例子,但没有一个对我有用。
【问题讨论】:
【参考方案1】:有两种方法可以做到这一点:
-
按原型
参考
但在我讨论这些之前——如果你在问题中展示的是关于你想做的事情的程度——让我建议List::MoreUtils::pairwise
那么,你会在哪里写这个:
my @sum = two_array_sum( @a, @b )
你只需写这个:
my @sum = pairwise $a + $b @a, @b;
按原型
这类似于push
。 (就像 push
它要求在 something 上有一个 @
印记)
sub two_array_sub (\@\@)
my ( $aref, $bref ) = @_;
...
当你这样做的时候就这样
two_array_sub( @a, @b );
它有效。而通常它只会在您的子列表中显示为一个长列表。正如您将在下面的讨论中看到的那样,它们并不适合所有人。
参考
这是每个人都向您展示的方式。
some_sub( \@a, \@b );
关于原型
他们很挑剔。如果您有 refs,这将不起作用:
two_array_sub( $arr_ref, $brr_ref );
你必须像这样传递它们:
two_array_sub( @$arr_ref, @$brr_ref );
但是,由于数组嵌套很深,使“数组表达式”变得真的很快变得丑陋,我经常避免 Perl 的麻烦,因为你可以通过将它放在“字符”中来重载 Perl 将采用的引用类型类”构造。 \[$@]
表示引用可以是标量或数组。
sub new_two_array_sub (\[$@]\[$@])
my $ref = shift;
my $arr = ref( $ref ) eq 'ARRAY' ? $ref : $$ref; # ref -> 'REF';
$ref = shift;
my $brr = ref( $ref ) eq 'ARRAY' ? $ref : $$ref;
...
所以所有这些工作:
new_two_array_sub( @a, $self->a_levelan_array );
new_two_array_sub( $arr, @b );
new_two_array_sub( @a, @b );
new_two_array_sub( $arr, $self->a_levelan_array );
然而,Perl 仍然对此很挑剔……出于某种原因:
new_two_array_sub( \@a, $b );
OR
new_two_array_sub( $a, [ 1..3 ] );
或任何其他仍可被视为对数组的引用的“构造函数”。幸运的是,你可以用旧的 Perl 4 &
&new_two_array_sub( \@a, [ 1..3 ] );
然后子中的复用代码负责处理两个数组引用。
【讨论】:
【参考方案2】:将数组的引用传递给函数:
two_array_sum( \@a, \@b )
并且不要使用a
或b
作为变量名,因为$a
和$b
是特殊的(用于排序)。
【讨论】:
【参考方案3】:我将引用 man perlref
的内容,但你应该全部阅读:
Making References
References can be created in several ways.
1. By using the backslash operator on a variable, subroutine, or
value. (This works much like the & (address-of) operator in C.)
This typically creates another reference to a variable, because
there's already a reference to the variable in the symbol table.
But the symbol table reference might go away, and you'll still have
the reference that the backslash returned. Here are some examples:
$scalarref = \$foo;
$arrayref = \@ARGV;
$hashref = \%ENV;
$coderef = \&handler;
$globref = \*foo;
...
Using References
That's it for creating references. By now you're probably dying to
know how to use references to get back to your long-lost data. There
are several basic methods.
1. Anywhere you'd put an identifier (or chain of identifiers) as part
of a variable or subroutine name, you can replace the identifier
with a simple scalar variable containing a reference of the correct
type:
$bar = $$scalarref;
push(@$arrayref, $filename);
$$arrayref[0] = "January";
$$hashref"KEY" = "VALUE";
&$coderef(1,2,3);
print $globref "output\n";
【讨论】:
@leden,perldoc 文章 perllol(Lists of Lists:perldoc.perl.org/perllol.html)和 perldsc(Data Structures Cookbook:perldoc.perl.org/perldsc.html)也可能有用。他们有很多具体的例子。 我同意您上面关于 Axeman 的回答客观/具体地更好的评论,但经过这么多年,我仍然没有足够地使用手册页。我想,用 PERL 学习它的方法不止一种。【参考方案4】:my @sums = two_array_sum(\@aArray, \@bArray);
sub two_array_sum # two_array_sum ( (1 2 3 4), (2, 4, 0, 1) ) -> (3, 6, 3, 5)
my ($aRef, $bRef) = @_;
my @result = ();
my $idx = 0;
foreach my $aItem (@$aRef)
my $bItem = $bRef->[$idx++];
push (@result, $aItem + $bItem);
return @result;
【讨论】:
那就是:my $bItem = $bRef->[$idx++];
【参考方案5】:
您不能将数组传递给函数。函数只能接受参数的标量列表。因此,您需要传递提供足够数据的标量来重新创建数组。
最简单的方法是传递对数组的引用。
sub two_array_sum
my ($array0, $array1) = @_;
my @array0 = @$array0;
my @array1 = @$array1;
return map $array0[$_] + $array1[$_] 0..$#array0;
您甚至可以避免重构数组并直接使用引用。
sub two_array_sum
my ($array0, $array1) = @_;
return map $array0->[$_] + $array1->[$_] 0..$#$array0;
用法:
my @array0 = (1, 2, 3, 4);
my @array1 = (2, 4, 0, 1);
two_array_sum(\@array0, \@array1);
方括号构造一个匿名数组(用其中的表达式的结果填充)并返回对该数组的引用。因此,上面也可以写成:
two_array_sum([1, 2, 3, 4], [2, 4, 0, 1]);
【讨论】:
@kindahero,是的。第二个使用的内存不超过返回结果所需的内存。如果返回值是数组引用,它可以使用更少的内存(通过从map
切换到for
)。【参考方案6】:
您需要使用引用将数组或哈希传递给您的子例程,例如:
sub two_array_sum
my ($x, $y) = @_;
#process $x, $y;
two_array_sum(\@a, \@b);
【讨论】:
这只是把第一个数组的第一个值放在$x中,把第一个数组的第二个值放在$y中。【参考方案7】:这些方法是规范的。另一种方法:
use strict;
my $data;
@$data->array1 = qw(foo bar baz);
@$data->array2 = qw(works for me);
testsub($data);
sub testsub
my ($data) = @_;
print join "\t", @$data->array1, "\n";
print join "\t", @$data->array2, "\n";
$data->array1[3] = "newitem";
delete $data->array2;
push @$data->newarray, (1, 2, 3);
return $data;
当您这样做时,您可以更严格地控制您的变量,而不是让程序数据与配置信息混杂在一起。
一般来说,我在任何程序中的变量都不会超过三四个。
我还保留了一个系统——我使用列表哈希列表的哈希值。
$config->server[0]prod[0]input[0] = 'inputfile';
原因是,只要我每一种方式都保持一致,Data::Dumper
就可以转储整个结构——而且我可以更好地控制数据的范围,并且可以轻松地传递整个结构。
我经常发现自己将多个这样的结构传递给子例程。作为标量,它们通过得很好,谢谢。
【讨论】:
以上是关于将两个或多个数组传递给 Perl 子例程的主要内容,如果未能解决你的问题,请参考以下文章
如何让 VBA 子例程调用将数组传递给子例程中的另一个函数的函数