I have a very noob-ish question here regarding refs, though still confounding to me at the very least...
In the code example below, i'm trying to create a hash of arrays:
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper;
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Terse = 1;
$Data::Dumper::Quotekeys = 0;
my @a1 = ( 'a1', 1, 1, 1 );
my @a2 = ( 'a2', 2, 2, 2 );
my $a1_ref = \@a1;
my $a2_ref = \@a2;
my @a = ( $a1_ref, $a2_ref );
my %h = ();
for my $i ( 1 .. 2 ) {
$h{"$i"} = \@a;
}
say Dumper \%h;
The Dumper output is
{
'1' => [
[
'a1',
1,
1,
1
],
[
'a2',
2,
2,
2
]
],
'2' => $VAR1->{'1'}
}
The question here is:
why is $h{'2'} a reference to $h{'1'}? I'm trying to create a hash %h with identical key-values made of the @a array-of-arrays. I want each key-value of the hash to have it's own AoA based on @a, but i'm getting references to $h{'1'} instead. What am i doing wrong??
The Dumper output i'm trying to achive is:
{
'1' => [
[
'a1',
1,
1,
1
],
[
'a2',
2,
2,
2
]
],
'2' => [
[
'a1',
1,
1,
1
],
[
'a2',
2,
2,
2
]
]
}
Any help appreciated. thanks in advance!
-dan
A Perl reference is a scalar data type that holds the location of another value which could be scalar, arrays, or hashes. Because of its scalar nature, a reference can be used anywhere, a scalar can be used. You can construct lists containing references to other lists, which can contain references to hashes, and so on.
Creating a reference to a Perl array If we have an array called @names, we can create a reference to the array using a back-slash \ in-front of the variable: my $names_ref = \@names;. We use the _ref extension so it will stand out for us that we expect to have a reference in that scalar.
Similar to the array, Perl hash can also be referenced by placing the '\' character in front of the hash. The general form of referencing a hash is shown below. %author = ( 'name' => "Harsha", 'designation' => "Manager" ); $hash_ref = \%author; This can be de-referenced to access the values as shown below.
It's not that $h{'2'}
is a reference to $h{'1'}
, but that both are references to the same array, namely @a
. What you probably want is:
for my $i ( 1 .. 2 ) {
$h{"$i"} = $a[$i - 1];
}
which is equivalent to this:
$h{'1'} = $a[0]; # i.e., $a1_ref
$h{'2'} = $a[1]; # i.e., $a2_ref
which makes $h{'1'}
a reference to @a1
and $h{'2'}
a reference to @a2
.
Incidentally, you might find it helpful to use the notations [ ... ]
and { ... }
to create references to anonymous arrays and hashes (respectively). Since you never use @a1
and @a2
except via $a1_ref
and $a2_ref
, you might as well create the latter directly:
my $a1_ref = [ 'a1', 1, 1, 1 ]; # reference to a new array (no name needed)
my $a2_ref = [ 'a2', 2, 2, 2 ]; # ditto
Edited for updated question: To copy an array, you can write:
my @orig = (1, 2, 3);
my @new = @orig;
or:
my $orig_ref = [1, 2, 3];
my $new_ref = [@$orig_ref]; # arrayref -> array -> list -> array -> arrayref
In your case, if I understand you correctly, you need to perform a slightly "deep" copy: you don't just want two arrays with the same elements, you want two arrays whose elements are references to distinct arrays with the same elements. There's no built-in Perl way to do that, but you can write a loop, or use the map
function:
my @orig = ([1, 2, 3], [4, 5, 6]);
my @new = map [@$_], @orig;
So:
for my $i ( 1 .. 2 ) {
$h{"$i"} = [map [@$_], @a];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With