Let me start off with a simple minimal example:
use strict;
use warnings;
use Data::Dumper;
my %hash;
$hash{count} = 4;
$hash{elems}[$_] = {} for (1..$hash{count});
print Dumper \%hash;
Here is the result (reformatted):
$VAR1 = {
'count' => 4,
'elems' => [undef, {}, {}, {}, {}]
};
I do not understand, why did the first element of $hash{elems}
become an undef
?
I know there are probably easier ways to do what I am doing, but I am creating these empty hashes so that I can later do my $e = $hash{elems}[$i]
and continue to use $e
to interact with the element, eg continue the horror of nested structures with $e->{subelems}[0] = 100
.
CodePudding user response:
Array indices start at 0
in Perl (and in most programming languages for that matter).
In the 1st iteration of $hash{elems}[$_] = {} for (1..$hash{count});
, $_
is 1
, and you thus put {}
at index 1
of $hash{elems}
.
Since you didn't put anything at index 0
of $hash{elems}
, it contains undef
.
To remedy this, you could use push
instead of assigning to specific indices:
push @{$hash{elems}}, {} for 1 .. $hash{count};
push
adds items at the end of its first argument. Initially, $hash{elems}
is empty, so the end is the 1st index (0
).
Some tips:
The parenthesis are not needed in
for (1..$hash{count})
:for 1 .. $hash{count}
works just as well and looks a bit lighter.You could initialize your hash when you declare it:
my %hash = ( count => 4, elems => [ map { {} } 1 .. 4 ] );
Initializing
elems
with an arrayref of hashrefs is often useless, thanks to autovivification. Simply doing$hash{elems}[0]{some_key} = 42
will create an arrayref in$hash{elems}
, a hashref at index0
in this array, containing the keysome_key
with value42
.
In some cases though, your initialization could make sense. For instance, if you want to pass$hash{elems}
(but not$hash
) to a function (same thing if you want to pass$hash{elems}[..]
to a function without passing$hash{elems}
).