user2688673 user2688673 - 7 months ago 12
Perl Question

Hash reference - Reuse inner hash to store and retrieve next values

I am new to Perl programming and have to work on Hash of Hashes. I am trying to reuse

innerHash
variables to be dynamic in nature. And I expect the inner items to be stored in
outerHash
how ever many I have added. Below is my test program snippet.

use warnings;
sub testHash {
my %outerHash = ();

my %innerHash1 = ();
my %innerHash2 = ();

$innerHash1{"key1"} = "value1";
$innerHash1{"key2"} = "value2";
$innerHash1{"key3"} = "value3";
$outerHash{"Master1"} = \%innerHash1;

$innerHash2{"key4"} = "value4";
$innerHash2{"key5"} = "value5";
$innerHash2{"key6"} = "value6";
$outerHash{"Master2"} = \%innerHash2;

#delete $innerHash1{$_};
%innerHash1 = ();
#undef %innerHash1;

$innerHash1{"key7"} = "value7";
$innerHash1{"key8"} = "value8";
$innerHash1{"key9"} = "value9";
$outerHash{"Master3"} = \%innerHash1;

foreach $outerItem (keys %outerHash){
print "\n$outerItem: ";
foreach $innerItem (keys %{$outerHash{$outerItem}}){
print "\t $innerItem = $outerHash{$outerItem}{$innerItem}";
}
print "\n-------------------------------------------------------";
}
print "\n";
}

testHash;


Output:

Master3: key8 = value8 key7 = value7 key9 = value9
-----------------------------------------------------------------
Master2: key5 = value5 key6 = value6 key4 = value4
-----------------------------------------------------------------
Master1: key8 = value8 key7 = value7 key9 = value9
-----------------------------------------------------------------


I understand it's taking the newer reference of
innerHash1
while printing the items. What is the right way to have all the right elements in
outerHash
? In a real programming scenario I cannot declare n variables in advance.

Answer

You may be new to perl, but you understand the concept of pointers don't you? The code $outerHash{"Master1"} = \%innerHash1; means that "$outerHash{"Master1"} is assigned a pointer to %innerHash1". So what you're observing is correct and expected.

If you want to keep recreating %innerHash and adding it to %outerHash, you will need to do one of two things:

  • Assign by value. $outerHash{"Master1"} = {}; %{$outerHash{"Master1"}} = %innerHash1;
  • Only add %innerHash to %outerHash once per loop. Since %innerHash is redeclared within the loop, not outside of it, it goes out of scope every loop, but its contents will be kept in outerHash due to perl's reference counting. Depending on your perspective, this could be considered "trying to be too clever and potentially dangerous", but I think it's fine.