onegative has asked for the wisdom of the Perl Monks concerning the following question:

G'day Monks,
I am for the first time trying to understand how to hash hashes but I am not getting it...seems I don't have enough nerve cells firing correctly to get it from the meager examples I have seen...I have a set of data that in a specific format which I have included a sample below...then below it is my first attempt to understand the proper format of how to code a multi layered associative array...but I can't even get pass the syntax error on line 32 where I am trying to define the associative array...if I could get help just understanding the proper repeatable tree to build a multi layered associated array it would be GREATLY appreciated...thanks for your attention and help in advance.
Data Set:
wspmon03/DISK.ssd123/DSKAvgServ Wed Nov 30 00:01:27 2006 7.34562 Wed Nov 30 00:02:29 2006 3.31222 Wed Nov 30 00:03:33 2006 1.23511 Wed Nov 30 00:04:23 2006 4.97532 Wed Nov 30 00:05:37 2006 5.31112 Wed Nov 30 00:06:36 2006 6.22991 wspmon03/DISK.ssd126/DSKAvgServ Wed Nov 30 00:01:27 2006 7.34562 Wed Nov 30 00:02:29 2006 3.31222 Wed Nov 30 00:03:33 2006 1.23511 Wed Nov 30 00:04:23 2006 4.97532 Wed Nov 30 00:05:37 2006 5.31112 Wed Nov 30 00:06:36 2006 6.22991 wspmon03/DISK.ssd129/DSKAvgServ Wed Nov 30 00:01:27 2006 7.34562 Wed Nov 30 00:02:29 2006 3.31222 Wed Nov 30 00:03:33 2006 1.23511 Wed Nov 30 00:04:23 2006 4.97532 Wed Nov 30 00:05:37 2006 5.31112 Wed Nov 30 00:06:36 2006 6.22991

Code Attempt - my idea is to create a hash called %host where $inst (Disk Instance) is the key along with the $count (Number of Data Points) where Instance.Count are the key to each key of dayofweek, month, date, timing, year, dpoint...if I am over thinking this or completely missing the obvious please someone slap me so I understand...and thanks may I have another?
:-)
#!/usr/local/bin/perl use Data::Dumper; use strict; # filename like wspmon03.DSKAvgServ.log my $filename = $ARGV[0]; (my $hostname, my $parameter) = split("\.", $filename, 2); open(FDAT, $filename) || die "Can't open file: $filename - $!\n"; my $count = 0; my $inst = ""; my $previous_inst = "dummy"; while(<FDAT>) { if (/.*\/DISK\.(.*)\/.*/) { my $inst = $1; } else { if ($previous_inst ne $inst) { $count = 0; $previous_inst = $inst; } (my $dayofweek, my $month, my $date, my $timing, my $year, my +$dpoint) = split(); my %host ( $inst, $count => { 'dayofweek' => $dayofweek, 'mon +th' => $month, 'date' => $date, 'timing' => $timing, 'year' => $year, + 'dpoint' => $dpoint } ); $count=$count+1; } } print Dumper(%host); close (FDAT);

Replies are listed 'Best First'.
Re: How to Hash Hashes
by GrandFather (Saint) on Nov 30, 2006 at 04:17 UTC

    You probably don't actually want a hash of hash (HoH), but a HoA. Consider:

    use strict; use warnings; use Data::Dumper; my $inst; my %host; while(<DATA>) { if (/.*\/DISK\.(.*)\/.*/) { $inst = $1; next; } my ($dayofweek, $month, $date, $timing, $year, $dpoint) = split; push @{$host{$inst}}, { 'dayofweek' => $dayofweek, 'month' => $month, 'date' => $date, 'year' => $year, 'timing' => $timing, 'dpoint' => $dpoint }; } print Dumper(\%host); __DATA__ wspmon03/DISK.ssd123/DSKAvgServ Wed Nov 30 00:01:27 2006 7.34562 Wed Nov 30 00:02:29 2006 3.31222 Wed Nov 30 00:03:33 2006 1.23511 Wed Nov 30 00:04:23 2006 4.97532 Wed Nov 30 00:05:37 2006 5.31112 Wed Nov 30 00:06:36 2006 6.22991 wspmon03/DISK.ssd126/DSKAvgServ Wed Nov 30 00:01:27 2006 7.34562 Wed Nov 30 00:02:29 2006 3.31222 Wed Nov 30 00:03:33 2006 1.23511 Wed Nov 30 00:04:23 2006 4.97532 Wed Nov 30 00:05:37 2006 5.31112 Wed Nov 30 00:06:36 2006 6.22991 wspmon03/DISK.ssd129/DSKAvgServ Wed Nov 30 00:01:27 2006 7.34562 Wed Nov 30 00:02:29 2006 3.31222 Wed Nov 30 00:03:33 2006 1.23511 Wed Nov 30 00:04:23 2006 4.97532 Wed Nov 30 00:05:37 2006 5.31112 Wed Nov 30 00:06:36 2006 6.22991

    which has the advantage that you don't need to maintain a bogus item count to 'index' into your 'hash' for the individual server information.

    As an aside, your sample code had a nasty bug in it. You redefine $inst inside an if block, assigned a value to it (from $1), then throw the value away when the local instance of $inst goes out of scope at the end of the block.

    Update: readmore tags added by popular demand.


    DWIM is Perl's answer to Gödel
      Yes, Yes, Yes...Grandfather
      It took me a little while to comprehend what you coded but it makes sense to me now...seeing I can access everything independently based off Instance, Array Count and data_id...sweet...this is exactly what I was wanting to accomplish...I will definately put this knowledge to good use.
      $host{sd1}[0]{dpoint} $host{sd1}[1]{dpoint} $host{sd1}[2]{dpoint} $host{sd1}[3]{dpoint} $host{sd1}[4]{dpoint} $host{sd1}[5]{dpoint} $host{sd2}[0]{dpoint} $host{sd2}[1]{dpoint} $host{sd2}[2]{dpoint} $host{sd2}[3]{dpoint} $host{sd2}[4]{dpoint} $host{sd2}[5]{dpoint} $host{sd3}[0]{dpoint} $host{sd3}[1]{dpoint} $host{sd3}[2]{dpoint} $host{sd3}[3]{dpoint} $host{sd3}[4]{dpoint} $host{sd3}[5]{dpoint}
      Thank you so much Grandfather... And as a side note, your Grandson is a handsome fellow...I am sure you are very proud of him.
      I appreciate your help tremendously and take care.
Re: How to Hash Hashes
by Crackers2 (Parson) on Nov 30, 2006 at 15:37 UTC

    Maybe it's a typo, but you're missing an equal sign in your assignment. It should be

    my %host = ( $inst, $count => { 'dayofweek' => $dayofweek, 'month' => + $month, 'date' => $date +, 'timing' => $timing, 'year' => $year, 'dpoint' => $dpoint } );
      You're right, I didn't catch that, I guess I was looking to hard for a bigger problem with the syntax...thanks for pointing that out to me...