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

Alright, to begin, I am pretty much a Perl newbie, I only just started learning the language for a project with the help of the "Perl Cookbook" by O'Reilly that someone loaned me. This is my first post, so be kind.

My Problem is that I have created a complex (at least it seems complex to me in Perl as I am more used to C) data structure.

Basically the data structure looks like this: I have a hash table where I store the name of a server and a reference to another hash as a pair.
Within this second Hash, I store a Process ID and a reference to another Hash as a pair.
Within this third Hash, I store a FD (a column from the LSOF file) and a reference to an array as a pair.
In this array I store all the data from an LSOF line. Now I have checked this Data structure, and everything seems to be saved properly and nothing overwritten etc.

My Problem however is accessing this data with several foreach loops. Its probably best if I show you my Code:
17 foreach $server (keys %servers) #returns individual servers 18 { 19 print "$server\n"; 20 foreach $process (keys %{$servers{$server}}) #returns indi +vidual processes on a server 21 { 22 print "$process\n"; 23 foreach $processPart (keys %{$servers{$server{$pro +cess}}}) # returns part of a process 24 { 25 print "$processPart\n"; 26 } 27 } 28 }

now, this works up until the second level. It prints out all of the $server and $process values but does not print $processPart.

my problem I think is the line:

foreach $processPart (keys %{$servers{$server{$process}}})

what im trying to do here is return the keys of the the third hash (eventually I want to return the actual Array reference and later the actual data in the array, but this shouldn't be a problem once I get the past this step (I think).

Basically, how do I keep accessing deeper and deeper Nested Hashes/Arrays in a foreach in this manner?

I was also wondering if there was a better way rather than just nested foreach statements. Like I said I am new to Perl so forgive me if there is a really easy answer to this.

Looking forward to help as this has been bugging me for three days.

Replies are listed 'Best First'.
Re: Nested Hash/Arrays Access
by kennethk (Abbot) on Jul 20, 2009 at 14:52 UTC
    You are thinking about hashes of hashes in the incorrect way. Hash elements and array elements must be scalars, so when dealing with a complex structure you are really storing hash references (pointers to hashes) in the hash. So rather than the nested access approach you have, reading a deep entry should look like

    $servers{$server}{$process}

    which is short hand for

    $servers{$server}->{$process}

    This means, for iterating through a hash of hashes using keys, your code should look like:

    foreach $server (keys %servers) #returns individual servers { print "$server\n"; foreach $process (keys %{$servers{$server}}) #returns individu +al processes on a server { print "$process\n"; foreach $processPart (keys %{$servers{$server}{$proces +s}}) # returns part of a process { print "$processPart\n"; } } }

    For some more details on these types of structures, you should probably read perllol.

      thank you, this fixed my problem perfectly. i was thinking of it in a C way. thanks for the help
Re: Nested Hash/Arrays Access
by Unforgiven (Hermit) on Jul 20, 2009 at 14:50 UTC
    Maybe I'm just misreading, but why not store it in a flatter sort of data structure in the first place? It'd probably be much easier to work with. Something like:
    my %server = ( name => "SomeServer", pid => 8328, fd => "Some FD", lsof => [ <some array here> ], );
    You then could just have an array of these server hashes. Not quite what you were asking for, I know, but better to avoid a problem entirely than to solve it, I think.

    Note: Edited to fix typo, after being notified by AnomalousMonk (thanks!).
Re: Nested Hash/Arrays Access
by johngg (Canon) on Jul 20, 2009 at 22:54 UTC
    Now I have checked this Data structure, and everything seems to be saved properly and nothing overwritten etc.

    You don't say how you did the checking but, if you haven't found it already, Data::Dumper is a very useful tool when you need to inspect your data structures. This

    use strict; use warnings; use Data::Dumper; my %hash = ( this => [ 1, 2, 4, 8 ], that => { the => q{other} }, ); print Data::Dumper->Dumpxs( [ \ %hash ], [ qw{ *hash } ] );

    produces this

    %hash = ( 'that' => { 'the' => 'other' }, 'this' => [ 1, 2, 4, 8 ] );

    I hope this is helpful.

    Cheers,

    JohnGG

      i was until now using a program called DDD that someone recommended to debug the program and i used it to display/print the data structures. i will look into data dumper however, as it seems very helpful thanks for the info
Re: Nested Hash/Arrays Access
by ww (Archbishop) on Jul 20, 2009 at 22:04 UTC

    Side issue:

    The Cookbook is a wonderful resource, but for issues like yours, you may be better served by Learning Perl, 5th Ed (also available from Amazon et al; earlier eds will still be very helpful).