user1215331
user1215331

Reputation: 13

How to retrieve an array from a hash that has been passed to a subroutine in perl

I am trying to write a subroutine that takes in a hash of arrays as an argument. However, when I try to retrieve one of the arrays, I seem to get the size of the array instead of the array itself.

my(%hash) = (  );
$hash{"aaa"} = ["blue", 1];

_subfoo("test", %hash);

sub _subfoo {

    my($test ,%aa) = @_;

    foreach my $name (keys %aa) {
        my @array = @{$aa{$name}};
        print $name. " is ". @array ."\n";
    }
}

This returns 2 instead of (blue, 1) as I expected. Is there some other way to handle arrays in hashes when in a subroutine?

Apologies if this is too simple for stack overflow, first time poster, and new to programming.

Upvotes: 1

Views: 120

Answers (2)

mu is too short
mu is too short

Reputation: 434665

You're putting your @array array into a scalar context right here:

print $name. " is ". @array ."\n";

An array in scalar context gives you the number of elements in the array and @array happens to have 2 elements. Try one of these instead:

print $name . " is " . join(', ', @array) . "\n";
print $name, " is ", @array, "\n";
print "$name is @array\n";

and you'll see the elements of your @array. Using join lets you paste the elements together as you please; the second one evaluates @array in list context and will mash the values together without separating them; the third interpolates @array by joining its elements together with $" (which is a single space by default).

Upvotes: 10

TLP
TLP

Reputation: 67900

As mu is too short has mentioned, you used the array in scalar context, and therefore it returned its length instead of its elements. I had some other pointers about your code.

Passing arguments by reference is sometimes a good idea when some of those arguments are arrays or hashes. The reason for this is that arrays and hashes are expanded into lists before being passed to the subroutine, which makes something like this impossible:

foo(@bar, @baz);
sub foo {                        # This will not work
    my (@array1, @array2) = @_;  # All the arguments will end up in @array1
    ...
}

This will work, however:

foo(\@bar, \@baz);
sub foo {                  
    my ($aref1, $aref2) = @_;
    ...
}

You may find that in your case, each is a nice function for your purposes, as it will make dereferencing the array a bit neater.

foo("test", \%hash);  # note the backslash to pass by reference

sub foo {
    my ($test, $aa) = @_; # note use of scalar $aa to store the reference

    while (my ($key, $value) = each %$aa)) {  # note dereferencing of $aa
        print "$key is @$value\n";            # ...and $value
    }
}

Upvotes: 4

Related Questions