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.

Was it helpful?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top