in reply to Help with Hash of hashes, is there a better way?
There is an example in the pod for Data::Rmap that shows how to use it's rmap_to() function to traverse a structure maintaining local state (the path through the hashes). It could be used as a starting point to create a custom iterator function.
# Traverse a tree using localize state $tree = [ one => two => [ three_one => three_two => [ three_three_one => ], three_four => ], four => [ [ five_one_one => ], ], ]; @path = ('q'); rmap_to { if(ref $_) { local(@path) = (@path, 1); # ARRAY adds a new level to the pa +th $_[0]->recurse(); # does stuff within local(@path)'s scope } else { print join('.', @path), " = $_ \n"; # show the scalar's path } $path[-1]++; # bump last element (even when it was an aref) } ARRAY|VALUE, $tree; # OUTPUT # q.1 = one # q.2 = two # q.3.1 = three_one # q.3.2 = three_two # q.3.3.1 = three_three_one # q.3.4 = three_four # q.4 = four # q.5.1.1 = five_one_one
This would involve writing your own function that wrapped code something similar to the above, but localise the keys on the fly. You would pass a callback (function or block) to the wrapper function, and it would call your code, with the appropriate variables ($env, $platform, $host, $target etc.) set and localised. You write this once the call with different callbacks each time you need to iterate the structure. If this idea interests you, but you need a bit more info on implementing it /msg me.
The other thought that crossed my mind was if you only ever access this structure through iteration, rather than individual direct accesses, then a HoH is probably the wrong structure. An AoH would be easier to use in that case. It might look something like this (pseudo-code):
my @servers = ( { type => production | development, env => Windows | unix | Database, hostname => the hostname targets => [ name1 => [ #total, #free ]. name2 => [ #total, #free ], ... ], }, { type => production | development, env => Windows | unix | Database, hostname => the hostname targets => [ name1 => [ #total, #free ]. name2 => [ #total, #free ], ... ], }, ... );
And to iterate it:
use constant { TOTAL => 0, FREE => 1 }; for my @server ( @servers ) { printf "Server: %s type:%s Env: %s\n", $server->{ hostname }, $server->{ type }, $server->{ env }; for my $target ( @{ $server->{ targets } } ) { printf "\tTotal: %d Free: %d\n", @{ $target }[ TOTAL, FREE ]; } }
|
|---|