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

I am sorry for being repetitive (as per my previous posts) but can someone explain me the generic ways of printing the elements in hash of arrays if the keys are same in the hash table and also for the cases where there are multiple keys like $hash{key1}{key2}{key3}

Thanks.

  • Comment on Generic Way of printing of Hash of Array

Replies are listed 'Best First'.
Re: Generic Way of printing of Hash of Array
by shmem (Chancellor) on Feb 01, 2010 at 07:23 UTC
    can someone explain me the generic ways of printing the elements in hash

    The generic way is to get the values via their keys and print them. The keys can be gathered via keys and then be used as arguments to a for loop. You can also retrieve key/value pairs via each and wrap that into a while loop.

    That's all that can be said wrt generic ways. If you just want the entire structure dumped to have it at a glance, then

    use Data::Dumper; my %hash = ( # fill in blank ); print Data::Dumper->Dump([\%hash],[qw(hash)]);
Re: Generic Way of printing of Hash of Array
by Xiong (Hermit) on Feb 01, 2010 at 09:51 UTC
Re: Generic Way of printing of Hash of Array
by roboticus (Chancellor) on Feb 01, 2010 at 16:25 UTC

    snape:

    Here's a little thing I put together when I was trying to do something similar. It relies on the ref function. First here's the code:

    #!/usr/bin/perl -w use strict; use warnings; my %xxx = (a=>5, b=>10, c=> {ca=>9, cb=>10}); my @yyy = ( [0, 1], {red=>2, blue=>3} ); my $aa = 5; my $bb=\%xxx; my $cc=\@yyy; print "aa=", thing_to_string($aa), "\n"; print "bb=", thing_to_string($bb), "\n"; print "cc=", thing_to_string($cc), "\n"; sub thing_to_string { my $t = shift; return '???UNDEF???' if !defined $t; if (ref $t eq '') { # It's a scalar, return it's value return $t; } elsif (ref $t eq 'ARRAY') { # It's an array, turn all the elements into strings, # separate them with commas, and wrap 'em in '(' and ')' return "(".join(", ", map { thing_to_string($_) } @$t ).")"; } elsif (ref $t eq 'HASH') { # It's a hash, turn all the elements into "key:value", # separate them with commas, and wrap 'em in '{' and '}' return "{".join(", ", map { $_."=>".thing_to_string($$t{$_}) } sort keys %$t)."}"; } # some other thing... return "...other..."; }

    The first trick is knowing what you're trying to turn into a string. Perl gives us the ref operator for that. It's a pretty nifty operator. It returns an empty string if you hand it a scalar (i.e. not a reference):

    [10:41:17] ~ $ perl -e '$a=5; print ref($a)' [10:41:29] ~ $

    If you hand it a reference to a scalar it'll return 'SCALAR'. Similarly, if you hand it a reference to an array or hash, it will return 'ARRAY' or 'HASH', accordingly:

    [10:41:29] ~ $ perl -e '$a=5; print ref(\$a)' SCALAR [10:43:19] ~ $ perl -e '@a=(1,2); print ref(\@a)' ARRAY [10:43:23] ~ $ perl -e '%a=(1=>0,2=>0); print ref(\%a)' HASH [10:43:26] ~ $

    Now that we know how to recognize *what* we're supposed to turn into a string, we just need to figure out how to do it. For a scalar it's easy--perl already treats a scalar as a string, so we just return the value.

    An array is only slightly trickier: We first need to turn all the array elements into strings. Once we do that, we can join all the items together with commas between them, then wrap it all up in parenthesis and return it as a string.

    For a hash, we get a list of the keys and use that list to access the elements. We turn the elements into strings, and then add the key value and "=>" to the front of each one. Then, like we do for arrays, we separate all the items with commas, then wrap in braces and return it as a string.

    The final trick: When we need to turn the array or hash elements into strings, the function calls itself to do so.

    1. So, in our first call to thing_to_string (with $cc) we find that $cc holds a reference to an array. So we call thing_to_string on the items in the array.
      1. Now we call thing_to_string on the first thing in the array $cc references--and find out that it's another array reference.
        1. So we call thing_to_string on the first thing in *that* array, and find the scalar 0, so we return 0.
        2. We call thing_to_string on the next thing in the array and find the scalar 1, so thing_to_string returns 1.
      2. At this point, there are no more things in the array, so thing_to_string glues builds the string '(0, 1)' and returns it.
    2. We next call thing_to_string on the next item in our array, and find a reference to a hash.
      1. So we get the list of keys to the hash: 'blue' and 'red'.
        1. We call thing_to_string to convert the thing that hash key 'blue' points to and receive '3'.
      2. Then we add the key with "=>" to make the chunk of string 'blue=>3'.
        1. We next call thing_to_string to convert the thing that hash key 'red' points to and receive 2.
      3. We again add the key and make a chunk of string 'red=>2'.
      4. Then, since there are no more hash keys, we wrap it all up into '{blue=>3, red=>2}' and return it.
    3. Now, this copy of thing_to_string runs out of items in the array. It has received '(0, 1)' for the first item, and '{blue=>3, red=>2}' for the second item, so all it has to do is join them with a comma, wrap it up in parenthesis and return it: '((0, 1), {blue=>3, red=>2})'

    ...roboticus

Re: Generic Way of printing of Hash of Array
by apl (Monsignor) on Feb 01, 2010 at 13:52 UTC