views:

149

answers:

3

Is it possible to pass two lists to a sub in Perl, for example:

sub Foo {
 my(@list1,@list2) = @_;

}

I know I could make @_ two lists, with each sublist being the desired argument, I'm just wondering if there is a cleaner way

+9  A: 

Well if you want two arrays you could use a prototype:

sub foo (\@\@) {
   my $arr1 = shift;
   my $arr2 = shift;

   # Access arrays as references
}

foo( @wiz, @waz );  # @wiz and @waz won't be flattened.

But there are many ways to get around prototypes, and I prefer to avoid them in most places. You can simply skip the prototype and manually pass references:

sub foo {
   my $arr1 = shift;
   my $arr2 = shift;

   # Access arrays as references
}

foo( \@wiz, \@waz ); # Pass in wiz/waz as refs
foo( [1,2,4],[3,5,6] );  # Hard coded arrays

If you haven't worked with references at all, check out perlreftut for a nice tutorial.

daotoad
it would seem that the prototype is a better solution, as it would not require the user to do anything special to pass the list arguments. thanks
Mike
@Mike, I would recommend against prototypes, since an experienced perl programmer will be more surprised by them than the requirement to pass a reference. Check out http://stackoverflow.com/questions/297034/why-are-perl-function-prototypes-bad for more on why prototypes are frowned upon.
daotoad
@Mike, I use prototypes soo often that I made an error in my prototype specification that I just realized. So if you already tried my code sample and it didn't work, note the change in the prototype.
daotoad
Indeed, prototypes are best avoided. You may also run into surprising results if you try to call a prototyped sub as an object method.
Ether
reference prototypes can be a bit annoying when you are trying to pass in a inline generated value without an intermediate array (output of `map` or `grep` for example). the non reference prototypes can be very useful though. the latter `foo` example can also be called this way: `foo \\(@wiz, @waz)`
Eric Strom
You have this really bad habit of highlighting the wrong answer by putting it first (and even mentioning it).
brian d foy
@Eric: maybe it's annoying because you're making it harder than it needs to be. Just use an anonymous array constructor around whatever is making the list: [ map {} ... ]. Easy Peasy.
brian d foy
@brian d foy => passing an anonymous array to a function with a `(\@)` prototype is a syntax error. It needs to be `@{[ map {} ... ]}` ... which ultimately doesn't help with readability and is just working around what should be an entirely unambiguous situation that the lexer/parser just doesn't understand.
Eric Strom
Well, that's one of the reasons you shouldn't use prototypes. I'm only talking about sane solutions.
brian d foy
+5  A: 

If you pass two lists by value ... you're going to get one big list in @_.

my(@list1,@list2) = @_; doesn't make any sense:

#!/usr/bin/perl

sub test
{
    my (@a, @b) = @_;

    print "@a\n";
    print "@b\n";
}

my @array1 = (1,2,3);
my @array2 = (5,6,7);

test(@array1, @array2);

This will end up printing:

1 2 3 5 6 7
<blank line> 

To pass two arrays, you'd need to pass them by reference:

test(\@array1, \@array2);

And in your sub you'd need to treat them as references:

sub test
{
    my ($arrayRef1, $arrayRef2) = @_;
    print "@$arrayRef1\n";
    print "@$arrayRef2\n";
}
Brian Roach
A: 


sub in_both{
my %a = @_;
my @first = @{$a{first}};
my @second= @{$a{second}};

}

@in_both=in_both(first=>[@names_one], second=>[@names_two]);


Hermann Ingjaldsson