Передача двух или более массивов в подпрограмму Perl

У меня возникают проблемы с передачей и чтением аргументов внутри подпрограммы, которая, как ожидается, будет иметь два массива.

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 он требует наличия @ sigil на чем-то)

sub two_array_sub (\@\@) { 
    my ( $aref, $bref ) = @_;
    ...
}

Таким образом, когда вы делаете это

two_array_sub( @a, @b );

он работает. В то время как обычно это будет просто отображаться в вашем суде как один длинный список. Они не для всех, как вы увидите в моем обсуждении ниже.

По ссылке

То, как все вас показывают.

some_sub( \@a, \@b );

О прототипах

Они изящны. Это не будет работать, если у вас есть ссылки:

two_array_sub( $arr_ref, $brr_ref );

Вы должны передать их следующим образом:

two_array_sub( @$arr_ref, @$brr_ref );

Однако, поскольку создание "выражений массива" становится очень уродливым быстро, когда массивы вложены вглубь, я часто избегаю сложности Perl, так как вы можете перегрузить тип ссылки, которую Perl возьмет, поставив ее в конструкцию "character class". \[[email protected]] означает, что ссылка может быть либо скаляром, либо массивом.

sub new_two_array_sub (\[[email protected]]\[[email protected]]) { 
    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 примерно со старым 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 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 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";

Ответ 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;
}

Ответ 5

Вам нужно передать массивы или хеши в свою подпрограмму, используя ссылки, например:

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

Ответ 6

Вы не можете передавать массивы в функции. Функции могут принимать только списки скаляров для аргумента. Таким образом, вам необходимо передать скаляры, которые предоставляют достаточные данные для воссоздания массивов.

Простейшим способом этого является передача ссылок на массивы.

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

Ответ 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 может сбросить всю структуру - и я могу лучше контролировать объем данных и легко пропускать целые структуры.

Я часто нахожу, что передаю несколько структур, подобных этому, подпрограмм. Как скаляры, они проходят довольно хорошо, спасибо.