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

I have a problem. I have a collection of hashes. The hashes should have a name associated to them so. The names are consisting of a alphabetic part and a numeric part for example they should have names like 'A1' or 'B2'. The various hashes in the hashcollection will vary at different time but there will allways be a so many hashes that they will be possible to print in a squere fashion like in this examples:
A1 A2
B1 B2

or

A1 A2 A3
B1 B2 B3

or

A1 A2
B1 B2
C1 C2

etc.

In the examples obove. Each name A1, B2 etc. will be a hash which should be printed out so The first example should for example when outprinted look something like:

#######################
A1................#A2................#
.bl=>0..........#.cc=>5...........#
.ff=>4..........#.dd=>4..........#
.gg=>3..........#.ee=>9..........#
#######################
B1................#B2................#
.og=>0.........#.oo=>5.........#
.wo=>4........#.pp=>4.........#
.ee=>3..........#.zz=>9..........#
#######################

Do you have any suggestions how I should do this in the best way? Which complex data stucture to use etc.?
Thank you for any help.

Replies are listed 'Best First'.
Re: Hash printing problem
by GrandFather (Saint) on Mar 05, 2006 at 20:31 UTC

    The following first builds a hash of alpha keys containing the individual keys, then uses that to generate the table.

    use strict; use warnings; my %hoh = ( A1 => {bl=>0, ff=>4, gg=>3}, A2 => {cc=>5, dd=>4, ee=>9}, B1 => {og=>0, wo=>4, ee=>3}, B2 => {oo=>5, pp=>4, zz=>9}, ); my %alphaKeys; push @{$alphaKeys{(/^([a-z]+)/i)[0]}}, $_ for keys %hoh; keys %hoh; for (sort keys %alphaKeys) { my @lines; for my $key (@{$alphaKeys{$_}}) { my $index = 0; $lines[$index++] .= sprintf "%-20s", $key; my %items = %{$hoh{$key}}; $lines[$index++] .= sprintf "%-20s", "$_=>$items{$_}" for sort + keys %items; } print "$_\n" for @lines; print "\n"; }

    Prints:

    A1 A2 bl=>0 cc=>5 ff=>4 dd=>4 gg=>3 ee=>9 B1 B2 ee=>3 oo=>5 og=>0 pp=>4 wo=>4 zz=>9

    Update: changed map to for per Tye's suggestion


    DWIM is Perl's answer to Gödel
      map {my $key = $_; $key =~ s/^([a-z]+­).*/$1/i; push @{$alphaKe­ys{$ke +y}}, $_} keys %hoh;

      Obfuscatory map in void context. I especially like the ", $_" you threw on the end so that map would return something meaningful (but useless) to its void context.

      for( keys %hoh ) { push @{ $alphakeys{ (/^([a-z]+)/)[0] } }, $_; }

      Though I'm guessing this is just a result of an incomplete refactoring.

      - tye        

        Opps. Yes you are right. There had been an assignment to an array, but it turned out messy. The array went, but not some of the cargo :).

        Thanks for pointing it out. Fixing a couple of transcription errors and turning things around a little I'd write it as:

        push @{$alphaKeys{(/^([a-z]+)/i)[0]}}, $_ for keys %hoh;

        DWIM is Perl's answer to Gödel
Re: Hash printing problem
by matze (Friar) on Mar 05, 2006 at 20:40 UTC
    This is a first short hack. I hope this helps you:
    #!/usr/bin/perl use warnings; use strict; my %hoh = ( "A1" => { "bl" => 0, "ff" => 4, "gg" => 3 }, "A2" => { "cc" => 5, "dd" => 4, "ee" => 9 }, "B1" => { "og" => 0, "wo" => 4, "ee" => 3 }, "B2" => { "oo" => 5, "pp" => 4, "zz" => 9 } ); # The names of the hashes to print my @keys_to_sort = sort keys %hoh; # As long we still have hashes to print while ( @keys_to_sort ) { # Extract hashes to use in current row # Smarter way to get the first part of the hash name? my $last = substr $keys_to_sort[0], 0, 1; my @keys_to_use; for ( my $i = 0; $i < @keys_to_sort; $i++ ) { if ( $keys_to_sort[$i] =~ /^$last/ ) { push @keys_to_use, splice( @keys_to_sort, $i, 1 ); $i--; } } print "\n", join( "\t", @keys_to_use ), "\n"; # Print key number $i of every hash in the array # Exchange keys %... with maximum number of keys in @keys_to_use for ( my $i = 0; $i < keys %{$hoh{$keys_to_use[0]}}; $i++ ) { # Print hashes - This relies on all hashes having # the same number of keys print join( "\t", map { my @keys_of_hash = sort keys %{$hoh{$_}}; $keys_of_hash[$i] . "=>" . $hoh{$_}{$keys_of_hash[$i]}; } @keys_to_use ), "\n"; } }
    I get this as output:
    A1 A2 bl=>0 cc=>5 ff=>4 dd=>4 gg=>3 ee=>9 B1 B2 ee=>3 oo=>5 og=>0 pp=>4 wo=>4 zz=>9
    As said in the program, this piece of code relies on every hash to have the same number of keys and that the keys remain the same while looping over them. This could be improved by replacing keys %{$hoh{$keys_to_use[0]}} with a function that determines the maximum of keys.

    I think here are some more flaws in it, but I hope that I could help you.
      Thanks God that all you skilled and friendly people exist. I think this would take me a week to figure out by myself. I will thank you all, and Perlmonks site exsplictly in my publication of the project Im doing.