将两个或多个数组传递给Perl子例程

时间:2011-04-15 17:13:46

标签: arrays perl parameter-passing subroutine

我在子程序中传递和读取参数时遇到问题,该子程序应该有两个数组。

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

我已经在网上看过并尝试了几个例子,但没有一个适合我。

7 个答案:

答案 0 :(得分:29)

有两种方法可以做到这一点:

  1. by prototype
  2. 参考
  3. 但在我讨论这些之前 - 如果你在问题中显示的是关于你想做什么的程度 - 让我建议List::MoreUtils::pairwise

    那么,你要写下这个:

    my @sum = two_array_sum( @a, @b )
    

    你只需写下:

    my @sum = pairwise { $a + $b } @a, @b;
    

    原型

    这就像push一样。 (就像push一样,它需要在某事上有@ sigil)

    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_level}{an_array} );
    new_two_array_sub( $arr, @b );
    new_two_array_sub( @a, @b );
    new_two_array_sub( $arr, $self->{a_level}{an_array} );
    

    然而,由于某种原因,Perl对此仍然很挑剔:

    new_two_array_sub( \@a, $b );
    OR 
    new_two_array_sub( $a, [ 1..3 ] );
    

    或者任何其他“构造函数”仍然可以被视为对数组的引用。幸运的是,您可以使用旧的 Perl 4 &

    关闭Perl。
    &new_two_array_sub( \@a, [ 1..3 ] );
    

    然后子中的多路复用代码负责处理两个数组引用。

答案 1 :(得分:7)

将对数组的引用传递给函数:

two_array_sum( \@a, \@b )

并且不要使用ab作为变量名称,因为$a$b是特殊的(用于排序)。

答案 2 :(得分:6)

我会引用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";

答案 3 :(得分: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;
}

答案 4 :(得分:2)

您需要使用引用将数组或哈希值传递给子例程,例如:

sub two_array_sum {
  my ($x, $y) = @_;
  #process $x, $y;
}
two_array_sum(\@a, \@b);

答案 5 :(得分:2)

您无法将数组传递给函数。函数只能接受参数的标量列表。因此,您需要传递提供足够数据的标量来重新创建数组。

最简单的方法是将引用传递给数组。

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]);

答案 6 :(得分:0)

这些方法都是规范的。另一种方法:

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就可以转储整个结构 - 我可以更好地控制数据范围,并且可以轻松地传递整个结构。 / p>

我经常发现自己将这样的多个结构传递给子程序。作为标量,他们通过得很好,谢谢。