1

I have an array and hash defined as:

my @test_array;

my %test_hash = (
    line_1 => 1,
    line_2 => 2,
    line_3 => 3,
);

I want to add that hash to the array, then modify the hash and push any new versions to the array

push (@test_array, %test_hash);

$test_hash{line_1} = 2;
push (@test_array, %test_hash);

Finally, I need to call a method while passing in each hash in the array, one at a time:

for my $hash (@test_array) {
    $self->do_thing(%$hash)
}

However, when I print out the array it appears that both hashes are stored in a single element:

use Data::Dumper;
print Dumper (\@test_array);

### Begin Output ###
$VAR1 = [
          'line_1',
          1,
          'line_3',
          3,
          'line_2',
          2,
          'line_1',
          2,
          'line_3',
          3,
          'line_2',
          2
        ];

My method call should essentially look like the following, with line_1 => 2 in the hash on the second time through the loop:

$self->do_thing(
    line_1 => 1,
    line_2 => 2,
    line_3 => 3,
);

Can someone please explain why this is all being added to a single array element? I expect that the Dumper output would include a $VAR1 for the first hash pushed, and a $VAR2 for the second - however this is not the case.

Thanks!

1
  • 1
    Hashes and arrays can only contains scalars, not hashes and arrays. As a "workaround", we store references to hashes and arrays in hashes and arrays, since those are scalars. Commented Feb 1, 2021 at 20:28

1 Answer 1

3

You can't add a hash to an array, but you can add a reference to a hash:

push @array, \%hash;

All references are a scalar, and lists are collections of scalars. An array is a variable that holds a list.

And, when you want to pass a data structure to a subroutine and keep it intact (so, not listifying it as you see here), pass a reference. Since the subroutine gets a reference, it can change the hash directly.

$self->do_thing($hash);

Now is the tricky part. In the middle of your question you talk about updating the hash. There are two things I think you might mean.

  1. Since you have a reference to a hash, any changes you make to the original hash are already visible to the reference. They point to the same data.

  2. If you want to make a new hash to add to the array (in addition to the one you just added), you need to do more work. If you want different versions of the same thing, you can clone the hash. Storable comes with Perl and has the dclone function for that:

    use Storable qw(dclone);

    my %hash = ...;

    # now you have a completely disconnected copy (deep copy)
    push @array, dclone(\%hash);

    # change the hash. The reference in `@array` is not affected
    $hash{foo} = ...;
    
    # add an additional deep copy clone
    push @array, dclone(\%hash);

All of this is covered in Intermediate Perl, as well as docs such as Perl Data Structures Cookbook.

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

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.