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

Monks, I am fighting with a nasty little problem of finding out how many levels a HoHoH has for a particular key. I load a Hash with data from a file using Dumper and eval.
*rvd*startScript : /binlib/mdi/rv/etc/start_rvd *rvd*daemonPort : 7500 *rvd*rrcp*sendRate*bufferSize : 1000 chilsd03*rvd*daemonPort : 9000
I need to determine the value of daemonPort and all other variables. If I am running on chilsd03 the value would be 9000 but anywhere else it would be 7500. I refer to this as the scope of the variable being either global or local. I need to scope this further to instance where there can be lines like.
chilsd03*rvd*OUT*daemonPort : 9000
So, the problem I am facing is that I need to figure out a good way to "walk" the hash and load up global and local values but keeping the integrity of the instances. Ideally I need to end up with a hash of
0 'rvd' 1 HASH(0x83d6a40) 'daemonPort' => 7500 'daemonProtocol' => 'tcp' 'httpPort' => 7580 'reliability' => 60 'startScript' => '/binlib/mdi/rv/etc/start_rvd' 'version' => 6.9 4 'IN' 5 HASH(0x83d6b0c) 'daemonPort' => 7500 'daemonProtocol' => 'tcp' 'httpPort' => 8590 'instanceName' => 'IN' 'reliability' => 60 'startScript' => '/binlib/mdi/rv/etc/start_rvd' 'version' => 6.9 6 'instances' 7 ARRAY(0x83d68f0) 0 'rvd' 1 'IN' What I get instead 0 'rvd' 1 HASH(0x83d6938) 'daemonPort' => 7500 'daemonProtocol' => 'tcp' 'httpPort' => 7580 'reliability' => 60 'startScript' => '/binlib/mdi/rv/etc/start_rvd' 'version' => 6.9 2 'rrcp' 3 HASH(0x83d8818) 'daemonPort' => 7500 'daemonProtocol' => 'tcp' 'httpPort' => 7580 'reliability' => 60 'startScript' => '/binlib/mdi/rv/etc/start_rvd' 'transmissionBus' => HASH(0x83d87b8) 'driverName' => 'sink,1' 'numBuffers' => 500 'version' => 6.9 4 'OUT' 5 HASH(0x83d6a7c) 'daemonPort' => 9575 'daemonProtocol' => 'tcp' 'httpPort' => 9590 'instanceName' => 'OUT' 'reliability' => 60 'startScript' => '/binlib/mdi/rv/etc/start_rvd' 'version' => 6.9 10 'instances' 11 ARRAY(0x83d67ac) 0 'rvd' 1 'rrcp' 2 'OUT'

Replies are listed 'Best First'.
Re: How many levels of indirection in a Hash?
by Roy Johnson (Monsignor) on Jun 07, 2005 at 20:15 UTC
    Can you simplify the problem for us? For example, can you show us a structure that you start with, how it should come out, and what you've been getting instead?

    Caution: Contents may have been coded under pressure.
Re: How many levels of indirection in a Hash?
by demerphq (Chancellor) on Jun 07, 2005 at 22:02 UTC

    Just a little tip, when posting output of complex data structures use something better than the debugger dump facility. Use Data::Dumper or something like it. The output is much easier to read and understand.

    ---
    $world=~s/war/peace/g

Re: How many levels of indirection in a Hash?
by thundergnat (Deacon) on Jun 07, 2005 at 21:08 UTC

    Pardon me if I am misunderstanding your question, but I think this seems to be what you are looking for. "Reparent" the hash based on the existance of a 'process' key one level deep; or, if the key 'process' exists in the hash, treat that key as the root.

    use warnings; use strict; my %hash; $hash{three}{levels}{deep} = 7500; $hash{process}{three}{levels}{deep} = 9000; for my $process(qw/ process no_process /){ my $hashbase; if (exists $hash{$process}){ $hashbase = $hash{$process}; } else { $hashbase = \%hash; } print "$process - ",$hashbase->{three}{levels}{deep},"\n"; }
Re: How many levels of indirection in a Hash?
by cool_jr256 (Acolyte) on Jun 07, 2005 at 20:26 UTC
    I got a little headache trying to read your post... a little simplification of the problem at hand as suggested in previous node would be great...
Re: How many levels of indirection in a Hash?
by crusty_collins (Friar) on Jun 07, 2005 at 20:32 UTC
    Simplify this is tough but here it goes... I parse out a file with lines like
    *rvd*startScript : /binlib/mdi/rv/etc/start_rvd *rvd*daemonPort : 7500 chilsd03*rvd*daemonPort : 9000
    I need to determine the value of daemonPort. If I am running on chilsd03 the value would be 9000 but anywhere else it would be 7500. I refer to this as the scope of the variable being either global or local. I need to scope this further to instance where there can be lines like.
    chilsd03*rvd*OUT*daemonPort : 9000
    So, the problem I am facing is that I need to figure out a good way to "walk" the hash and load up global and local values but keeping the integrity of the instances. Ideally I need to end up with a hash of
    0 'rvd' 1 HASH(0x83d6a40) 'daemonPort' => 7500 'daemonProtocol' => 'tcp' 'httpPort' => 7580 'reliability' => 60 'startScript' => '/binlib/mdi/rv/etc/start_rvd' 'version' => 6.9 4 'IN' 5 HASH(0x83d6b0c) 'daemonPort' => 7500 'daemonProtocol' => 'tcp' 'httpPort' => 8590 'instanceName' => 'IN' 'reliability' => 60 'startScript' => '/binlib/mdi/rv/etc/start_rvd' 'version' => 6.9 6 'instances' 7 ARRAY(0x83d68f0) 0 'rvd' 1 'IN'
    What I get instead
    0 'rvd' 1 HASH(0x83d6938) 'daemonPort' => 7500 'daemonProtocol' => 'tcp' 'httpPort' => 7580 'reliability' => 60 'startScript' => '/binlib/mdi/rv/etc/start_rvd' 'version' => 6.9 2 'rrcp' 3 HASH(0x83d8818) 'daemonPort' => 7500 'daemonProtocol' => 'tcp' 'httpPort' => 7580 'reliability' => 60 'startScript' => '/binlib/mdi/rv/etc/start_rvd' 'transmissionBus' => HASH(0x83d87b8) 'driverName' => 'sink,1' 'numBuffers' => 500 'version' => 6.9 4 'OUT' 5 HASH(0x83d6a7c) 'daemonPort' => 9575 'daemonProtocol' => 'tcp' 'httpPort' => 9590 'instanceName' => 'OUT' 'reliability' => 60 'startScript' => '/binlib/mdi/rv/etc/start_rvd' 'version' => 6.9 10 'instances' 11 ARRAY(0x83d67ac) 0 'rvd' 1 'rrcp' 2 'OUT'
    I appologize for being so verbose.
Re: How many levels of indirection in a Hash?
by crusty_collins (Friar) on Jun 07, 2005 at 21:23 UTC
    Absolutely! Thanks for putting it that way. How do you find out how deep it goes? ... without cheating when you create the hash :)
    use warnings; use strict; my %hash; $hash{three}{levels}{deep} = 7500; $hash{process}{three}{levels}{deep} = 9000; $hash{process}{numberoflevels} = 4; for my $process(qw/ process no_process /){ my $hashbase; if (exists $hash{$process}){ $hashbase = $hash{$process}; } else { $hashbase = \%hash; } print "$process - ",$hashbase->{three}{levels}{deep},"\n"; }
      A HoH can go to varying depths. Do you want to traverse the whole HoH to find the deepest element, or do you know the chain you want to go down? The basic strategy is: if a value is a ref (ref $href->{$key} eq 'HASH') then descend a level ($href = $href->{$key}), increment your depth counter, and look again. The only tricky part is determining which keys you look at.

      Caution: Contents may have been coded under pressure.
Re: How many levels of indirection in a Hash?
by crusty_collins (Friar) on Jun 08, 2005 at 01:02 UTC
    Roy, thanks for the info. I think I can work with that.