Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Dereferencing a Hash of Hashes of Hashes?

by hsinclai (Deacon)
on Dec 04, 2007 at 20:50 UTC ( [id://654944]=perlquestion: print w/replies, xml ) Need Help??

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

Hi monks,

While I normally use this to grab Memcached statistics I was fooling around with Cache::Memcached's stats method which returns a hashref of statistical data. Dealing with that appeared do-able enough until I notice that the data returned from stats() looks like this:
$VAR1 = { 'hosts' => { '127.0.0.1:11211' => { 'misc' => { 'bytes' => ' +132677792', 'curr_connec +tions' => '1', 'connection_ +structures' => '3', 'pointer_siz +e' => '64', 'time' => '1 +196796974', 'total_items +' => '1900000', 'cmd_set' => + '1900000', 'bytes_writt +en' => '66197744', 'evictions' +=> '0', 'curr_items' + => '1900000', 'pid' => '18 +968', 'limit_maxby +tes' => '318767104', 'uptime' => +'1625', 'rusage_user +' => '13.501947', 'cmd_get' => + '1900000', 'rusage_syst +em' => '20.188930', 'version' => + '1.2.2', 'get_hits' = +> '1900000', 'bytes_read' + => '65067000', 'threads' => + '1', 'total_conne +ctions' => '41', 'get_misses' + => '0' }, 'sizes' => { '64' => '99 +9', '96' => '18 +99001' }, 'malloc' => { 'total_fre +e' => '6438240', 'releasabl +e_space' => '6425520', 'free_chun +ks' => '7', 'fastbin_b +locks' => '0', 'arena_siz +e' => '156471296', 'total_all +oc' => '150033056', 'max_total +_alloc' => '0', 'mmapped_r +egions' => '36', 'mmapped_s +pace' => '57696256', 'fastbin_s +pace' => '0' } } }, 'self' => {}, 'total' => { 'malloc_releasable_space' => 6425520, 'bytes' => 132677792, 'connection_structures' => 3, 'total_items' => 1900000, 'malloc_mmapped_regions' => 36, 'malloc_free_chunks' => 7, 'malloc_total_alloc' => 150033056, 'cmd_set' => 1900000, 'bytes_written' => 66197744, 'malloc_fastbin_blocks' => 0, 'curr_items' => 1900000, 'malloc_max_total_alloc' => 0, 'malloc_arena_size' => 156471296, 'malloc_mmapped_space' => 57696256, 'cmd_get' => 1900000, 'malloc_fastbin_space' => 0, 'get_hits' => 1900000, 'bytes_read' => 65067000, 'total_connections' => 41, 'malloc_total_free' => 6438240, 'get_misses' => 0 } };

Looking at the first key there, this seems to be a Hash of Hashes of Hashes - is there such a thing (perlreftut mentions nested hashes but deducing how to deal with them in that doc isn't immediately clear..)? If so, how would one dereference this?

While wanting to (as an exercise) loop through the keys and return all the data, the best I came up with is
my $hashref1 = $memd->stats(); while ( my ($k,$v) = each %$hashref1 ) { print $k . ' --> ' . $v . $/; while ( my ($KK,$VV) = each %$v ) { print $KK . ' --> ' . $VV . $/; } }
... which at least yeilds some data:
hosts -> HASH(0x30129a0) 127.0.0.1:11211 --> HASH(0x1b71da50) malloc_releasable_space --> 6425520 bytes --> 132677792 connection_structures --> 3 total_items --> 1900000 malloc_mmapped_regions --> 36 malloc_free_chunks --> 7 malloc_total_alloc --> 150033056 cmd_set --> 1900000 bytes_written --> 66210882 malloc_fastbin_blocks --> 0 curr_items --> 1900000 malloc_max_total_alloc --> 0 malloc_arena_size --> 156471296 malloc_mmapped_space --> 57696256 cmd_get --> 1900000 malloc_fastbin_space --> 0 get_hits --> 1900000 bytes_read --> 65067290 total_connections --> 66 malloc_total_free --> 6438240 get_misses --> 0

but only for one level of hashes ... making me feel much as if (as fenLisesi so eloquently put it) I'm carrying stones from the quarry :)

Obviously the pieces inside the data structure aren't built the same (from key to key) - each key could contain a hash or a further structure ... so,

  • is it possible to step through the hashref and return the data with some sort of magic/test to see what's there?
  • How can one tell if these keys would be returned in the same order every time from this (or similar) module?
  • Is this type of data structure encountered other times, with other modules?
  • If this is just a one-off occurrence, perhaps it's not even worth bothering with figuring out how to do this.

    Apologies since there are several questions here, many thanks for your insight,
    Harold

    Update: Thanks for pointing me in the right direction here CountZero and pKai

  • Replies are listed 'Best First'.
    Re: Dereferencing a Hash of Hashes of Hashes?
    by CountZero (Bishop) on Dec 04, 2007 at 21:13 UTC
      Hint: the trick is to check if the value of each key is a reference to a hash or array or ... and if so, just expand this value appropriately. It is probably a good candidate for some recursive code.

      From the docs:

      ref EXPR

      ref

      Returns a non-empty string if EXPR is a reference, the empty string otherwise. If EXPR is not specified, $_ will be used. The value returned depends on the type of thing the reference is a reference to. Builtin types include:
      • SCALAR
      • ARRAY
      • HASH
      • CODE
      • REF
      • GLOB
      • LVALUE
      If the referenced object has been blessed into a package, then that package name is returned instead. You can think of ref as a typeof operator.
      if (ref($r) eq "HASH") { print "r is a reference to a hash.\n"; } unless (ref($r)) { print "r is not a reference at all.\n"; }

      CountZero

      A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

    Re: Dereferencing a Hash of Hashes of Hashes?
    by pKai (Priest) on Dec 04, 2007 at 21:06 UTC

      perldoc perldsc will give you lots of information how to deal with that kind of structures. It's not that hard.

      Update: expanding more directly on you bulleted list:

      is it possible to step through the hashref and return the data with some sort of magic/test to see what's there?
      For the 1st part see perldsc. For the second part: ref
      How can one tell if these keys would be returned in the same order every time from this (or similar) module?
      There are modules that implement ordered hashes. But plain vanilla Perl hashes are unordered by design.
      Is this type of data structure encountered other times, with other modules?
      If this is just a one-off occurrence, perhaps it's not even worth bothering with figuring out how to do this.
      This is a weird question in my perception. This kind of structure is the bread and butter of every day perl programming.

    Log In?
    Username:
    Password:

    What's my password?
    Create A New User
    Domain Nodelet?
    Node Status?
    node history
    Node Type: perlquestion [id://654944]
    Approved by moritz
    help
    Chatterbox?
    and the web crawler heard nothing...

    How do I use this?Last hourOther CB clients
    Other Users?
    Others wandering the Monastery: (8)
    As of 2024-04-18 10:15 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found