views:

105

answers:

4

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.

+1  A: 

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;
}
jamessan
My problem is that I don't know how many %lineHash I need, because it is tied to the number of lines in a CSV read at runtime.
Mick
So what's the problem? You can say `$topHash{"line$line"} = $lineHashRef` and keep incrementing `$line` everytime you create an anonymous hash from a line in your CSV file.
mobrule
+3  A: 

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;
friedo
+1  A: 
#!/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";
    }
}
RC
A: 

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.

mobrule