0

I have the below code

    use strict;
    sub test {
       my($greeting, @names) = @_;
       my $returnString;

       foreach my $name (@names) {
           $returnString .= "$greeting, $name!\n";
       }

       return $returnString;
    }
    print &test("Hi", "Tim", "Tom", "Chris");

which outputs

    Hi Tim! Hi Tom! Hi Chris!

I want to be able to add multiple arrays. I tried modifying my code like the below

       my(@greeting, @names) = @_;
       print &test("Hi", "Tim", "Hello", "Tom", "Bye", "Chris");

However I have found that this can't be done. From the reading I have done I think I need to pass the arguments as references.

        my($greeting, $names) = @_;
        my @names = $names; 

But I have found this only outputs Hi Tim!

What is the best way to handle this situation?

4 Answers 4

4

You do need to pass them as references for the sub to receive them as two separate arrays rather than a single list, you just got the syntax wrong. Try this instead:

my @greetings = qw( Hi Hello );
my @names = qw( Tim Tom Chris );

# Put a \ before the variable to get a reference to it
say_greetings(\@greetings, \@names);

sub say_greetings {
  my ($greeting_ref, $name_ref) = @_;

  # Put @ before an arrayref to get the array back
  my @greet = @$greeting_ref;
...
}

Also, you shouldn't get in the habit of prefixing sub calls with &. It's a holdover from Perl 4. In Perl 5, it's not required and can have unexpected side-effects.

Sign up to request clarification or add additional context in comments.

Comments

3

The best way to handle this situation depends on your needs. Here are several options:

  1. List::MoreUtils 'natatime' (if order matters)

    use List::MoreUtils 'natatime';
    
    test( 'Hi', 'Tim', 'Hi', 'Tom' );
    
    sub test {
    
        warn( "Need to provide greeting-name pairs" ), # Check for
          return if @_ % 2;                            # data completeness
    
        my $iter = natatime, 2, @_;
    
        my $string;
        while ( my ( $greet, $name ) = $iter->() ) {
    
            $string .= "$greet $name!\n";
        }
    
        return $string;
    }
    
  2. Treat the list passed as a hash (if order doesn't matter):

    test( 'Hi', 'Tim', 'Hi', 'Tom' );
    
    sub test {
    
        my %set = @_;  # warnings pragma checks for
                       # data completeness during runtime
    
        return join "\n", map { "$_ $set{$_}!" } keys %set;
    }
    
  3. Pass key-value pairs as arrayrefs (preserves order, data completeness guaranteed):

    test( [ 'Hi', 'Tim' ], [ 'Hi', 'Tom' ] );
    
    sub test { join "\n", map { "@{$_}!" } @_ }
    

Comments

1

Hope this helps. If the greeting and names are always in order then the following code works.

use strict;

test("Hi", "Tim", "Hello", "Tom", "Bye", "Chris");

sub test
{
        my $i;
        my $len = @_;

        for ($i = 0; $i < @_; $i += 2) {
                print "$_[$i] $_[$i + 1]\n"
        }
}

Input validation is not done. Check for array length to be multiple of 2 would be good to go.

Comments

1

You don't have to use references, pass your list as it is and iterate over every second element as greeting and name are set in pairs.

use strict;
use warnings;

sub test {
   my @arg = @_;

   my $returnString = "";
   foreach my $i (grep { ! ($_%2) } 0 .. $#arg) {

       my ($greeting, $name) = @arg[$i, $i+1];
       $returnString .= "$greeting, $name!\n";
   }

   return $returnString;
}

print test("Hi", "Tim", "Hello", "Tom", "Bye", "Chris");    

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.