I needed to build a variable depth hash data structure in perl. Eventually I found this piece of code:
#!/usr/bin/perl -w
use strict;
my %hash;
my $value = "foo";
my @cats = qw(a b c d);
my $p = \%hash;
foreach my $item (@cats) {
$p->{$item} = {} unless exists($p->{$item});
$p = $p->{$item};
}
My question is how and why it works. I thought I knew how perl worked. At no point in this code do I see \%hash value being reset and it appears that $p (which is a local variable) is reset on every loop. I could even see it with data dumper: Running:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
my %hash;
my $value = "foo";
my @cats = qw(a b c d);
my $p = \%hash;
foreach my $item (@cats) {
print "BEFORE:\n";
print Dumper(\%hash);
#print Dumper($p);
$p->{$item} = {} unless exists($p->{$item});
$p = $p->{$item};
print "AFTER:\n";
print Dumper(\%hash);
#print Dumper($p);
}
And Then uncommenting the line with
#print Dumper($p) CLEARLY shows $p being a new variable every time.
How does \%hash gets build if $p is reset every time?
$p isn't being "reset" each time; it's being set to the next lower level in the hash, the one just added. At this point it is just an empty hashref, {}, because it will be filled in on the next loop iteration.
I'm not sure how you are concluding that $p is a new variable each time, but this is incorrect.. it's just pointing to a new location in the %hash structure. Since it was declared outside the loop, it doesn't lose its value as the loop iterates.
Add an explicit marker to the hash to which $p refers:
...
print "AFTER:\n";
$p->{'$p'} = 'is here!';
print Dumper(\%hash);
delete $p->{'$p'};
}
Then the last couple of AFTER dumps look like
AFTER:
$VAR1 = {
'a' => {
'b' => {
'c' => {
'$p' => 'is here!'
}
}
}
};
AFTER:
$VAR1 = {
'a' => {
'b' => {
'c' => {
'd' => {
'$p' => 'is here!'
}
}
}
}
};
Yes, at each new depth, $p refers to an empty hash, but take a step back to see the overall structure of %hash.
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