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


In reply to Re: Generic Way of printing of Hash of Array by roboticus
in thread Generic Way of printing of Hash of Array by snape

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.