How do I create and add anonymous hashes to a known Hash during script execution?
-
10-07-2019 - |
Question
I'll attempt to illustrate this with an example. Take a common example of a Hash of Hashes:
my %HoH = (
flintstones => {
lead => "fred",
pal => "barney",
},
jetsons => {
lead => "george",
wife => "jane",
"his boy" => "elroy",
},
simpsons => {
lead => "homer",
wife => "marge",
kid => "bart",
},
);
For my purposes, I would like to be able to add an unnamed, or anonymous hashes to %HOH. I won't need (or be able to) define these sub-hashes until runtime. How can I accomplish this with Perl?
Everything I've read (and I have read through Perldocs and Google'd already) seems to show examples where all sub-hahes (e.g. "flintstones", "jetsons", and "simpsons") are defined.
What I am doing is attempting to build a parent Hash that will contain sub-hashes with rows from a CSV file:
%TopHash = (
%Line1 => {
cell01 => $some_value1a;
cell02 => $some_value2a;
cell03 => $some_value3a;
},
%Line2 => {
cell01 => $some_value1b;
cell02 => $some_value2b;
cell03 => $some_value3b;
},
%Line3 => {
cell01 => $some_value1c;
cell02 => $some_value2c;
cell03 => $some_value3c;
},
# etc
# etc
# etc
);
The number of "%LineX" hashes that I need is not known until runtime (because they represent the number of lines in a CSV that is read at runtime).
Any ideas? If it isn't clear already...I still am trying to wrap my head around Perl hashes.
Solution
First you create the hash from the current line you're parsing
my %lineHash = (
cell01 => $some_value1a,
cell02 => $some_value1b,
cell03 => $some_value1c
);
or create a reference to a hash outright
my $lineHashRef = {
cell01 => $some_value2a,
cell02 => $some_value2b,
cell03 => $some_value2c
};
Then you add it to your overall hash, remembering that nested perl structures just contain references to the other structures.
$topHash{line1} = \%lineHash;
$topHash{line2} = $lineHashRef;
Updated Example given a loop over an array of data to parse
my %topHash;
foreach my $i (0 .. $#data) {
my %tempHash;
// stuff here to parse $data[$i] and populate %tempHash
$topHash{"line$i"} = \%tempHash;
}
OTHER TIPS
To add an anonymous hash at runtime, assign it as you would a normal hash element:
$HoH{key} = { foo => 42 };
or
$HoH{key} = $hash_ref;
or
$HoH{key} = \%hash;
#!/usr/bin/perl
use strict;
my %HoH = (
line01 => {
cell01 => "cell0101",
cell02 => "cell0102",
cell03 => "cell0103"
}
);
$HoH{"line02"} =
{
cell01 => "cell0201",
cell02 => "cell0202",
cell03 => "cell0203"
};
foreach my $hohKey (keys %HoH)
{
my $newHash = $HoH{$hohKey};
print "Line Name: $hohKey\n";
foreach my $key (keys %$newHash)
{
print "\t$key => ", $newHash->{$key}, "\n";
}
}
Everytime you create a new hash from a line of data, you'll need to think of a unique key to store that data in your top hash table.
my $line = 1;
my %HoH;
while (<>) {
my ($cell01, $cell02, $cell03, @etc) = split /,/;
my $newHash = { cell01 => $cell01, cell02 => $cell02, ... };
my $key = "line$line";
$HoH{$key} = $newHash;
$line++;
}
Now keys(%HoH)
will return a (unsorted) list like "line1","line2","line3",...
.
$HoH{"line5"}
would return a reference to the data for the 5th line of your file.
%{$HoH{"line7"}}
is kind of ugly syntax but it returns a hashtable of your data
from line 7.
$HoH{"line14"}{"cell02"}
could be used to get at a specific piece of data.