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

Greetings Monks,

I have two references to hashes of arrays: $best and $kept_best. Each array in $best will have 10 elements and each array in $kept_best will have at most 10. Both hashes have the same amount of keys and same key names. I would like to print them out side by side.

BEST SELECTED BEST best->Key1 kept_best->Key1 Key1->el1 Key1->el1 Key1->el2 Key1->el2 ... best->Key2 kept_best->Key2 Key2->el1 Key2->el1 Key2->el2 Key2->el2 ...
I have come up with:
print "BEST SELECTED BEST\n"; foreach my $value (sort keys %{$best}){ my $i = 0; foreach my $bind_energy (@{$best->{$value}}){ printf "%10.5f ", $bind_energy; if (defined($kept_best->{$value}->[$i])){ printf "%10.5f \n", $kept_best->{$value}->[$i]; $i++; } else { print "\n"; } } }
But I find my solution lacking in elegance and wit and wonder if the monks have a better way to do it?.

Thanks,

-tomdbs98

Replies are listed 'Best First'.
Re: Print multiple hashes of arrays at same time
by kennethk (Abbot) on Jul 19, 2010 at 18:38 UTC
    Elegance and wit are in the mind of the beholder - my favorite solutions are the ones that work and work reliably. In any case, since you have synchronized arrays, you have a couple of options for how to traverse them - e.g. you can either use an index variable as you have done or you can use shift to destructively-traverse one or more of the arrays, as I have done below. As well, rather than the branching you have done, I took advantage of the fact that printf silently drops unused terms to move the conditional into the format statement. I have also abstracted the field-size and precision to variables at the top of the script to aid in future-proofing.

    #!/usr/bin/perl use strict; use warnings; my $best = {1 =>[1,2]}; my $kept_best = {1 =>[1]}; my $width = 10; my $precision = 5; printf "%-${width}s %-${width}s\n", "BEST", "SELECTED BEST"; foreach my $value (sort keys %$best){ foreach my $bind_energy (@{$best->{$value}}){ my $kept = shift @{$kept_best->{$value}}; my $format = "\%${width}.${precision}f"; $format .= defined $kept ? " $format\n" : "\n"; printf $format, $bind_energy, $kept; } }

    If you find the variable $format approach unclear, you can achieve the same result by just using multiple printfs and an if conditional:

    #!/usr/bin/perl use strict; use warnings; my $best = {1 =>[1,2]}; my $kept_best = {1 =>[1]}; my $width = 10; my $precision = 5; my $format = "\%${width}.${precision}f "; printf "%-${width}s %-${width}s\n", "BEST", "SELECTED BEST"; foreach my $value (sort keys %$best){ foreach my $bind_energy (@{$best->{$value}}){ printf $format, $bind_energy; my $kept = shift @{$kept_best->{$value}}; printf $format, $kept if defined $kept; print "\n"; } }

    TIMTOWTDI.

      It took me a few minutes to understand your use of format in the first example, but I love it, very clever.
Re: Print multiple hashes of arrays at same time
by toolic (Bishop) on Jul 19, 2010 at 18:42 UTC
    This may be slightly more readable. Since it accesses elements of both arrays in the same way (using an index), it is a bit more consistent. It also eliminates the explicit $i++;. You can decide if it is better.
    print "BEST SELECTED BEST\n"; foreach my $value (sort keys %{$best}) { foreach my $i (0 .. $#{$best->{$value}}) { printf "%10.5f ", $best ->{$value}[$i]; printf "%10.5f" , $kept_best->{$value}[$i] if defined $kept_best->{$value}[$i]; print "\n"; } }
      Yes, the explicit  $i++ was what was really bugging me.
Re: Print multiple hashes of arrays at same time
by BrowserUk (Patriarch) on Jul 19, 2010 at 19:03 UTC

    use List::Util qw[ shuffle ];; %h1 = map{ ("key$_", "value$_" ) } 0 .. 9;; @selected = (shuffle keys %h1 )[ 0 .. 4 ];; @h2{ @selected } = @h1{ @selected };; printf "%-20s %-20s\n", $h1{ $_ }, $h2{ $_ } // '' for sort keys %h1;; value0 value0 value1 value1 value2 value2 value3 value4 value4 value5 value6 value6 value7 value8 value9

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      This looks awesome, but I can't get it to compile.
      syntax error at testcode/test.pl line 10, near "@h2{ "
      Too bad I don't have the knowledge base to debug it D:
        It works for me. I copy'n'pasted the 5 lines of Perl code, and I am able to reproduce BrowserUk's results without any errors.
        Your issue may be related to use strict;. @h2{ @selected } = @h1{ @selected }; uses hash slices to copy values from one hash to another. However, if you simply affix a my, perl will interpret that as a malformed array declaration. If this sounds like your issue, precede the line in question with the statement my %h2;.
Re: Print multiple hashes of arrays at same time
by biohisham (Priest) on Jul 20, 2010 at 05:02 UTC

    Text::Table seems handy.

    Having two hashes with the same keys, while one of these two hashes (%$keep_best) has at most three elements for each array associated with each one of its keys the other one has a 3-array element associated with each key. So looping through the hash %$best keys and associated array elements is sufficient to blanket elements in the hash %$keep_best as well..values in %$best are completed in %$keep_best (i.e $best{key1}= [1,2,3], $keep_best{key1}=[4,5])..
    use strict; use Text::Table; my $best = {'key1'=>[1,2,3],'key2'=>['f','g','h'],'el1'=>['y','z','z1' +]}; my $keep_best = {'key1'=>[4,5], 'el1'=>['w','x'],'key2'=>['i','j','k'] +}; my $table = Text::Table->new("key\n---","BEST\n----","KEEP BEST\n----- +--"); foreach my $key (sort keys %$best){ $table->add($key,@{$best->{$key}}[$_],@{$keep_best->{$key}}[$_]) for (0..$#{$be +st->{$key}}); } print $table;
    OUTPUT:
    key BEST KEEP BEST --- ---- --------- el1 y w el1 z x el1 z1 key1 1 4 key1 2 5 key1 3 key2 f i key2 g j key2 h k


    Excellence is an Endeavor of Persistence. A Year-Old Monk :D .
Re: Print multiple hashes of arrays at same time
by aquarium (Curate) on Jul 19, 2010 at 23:29 UTC
    Is it a true requirement to have the two hashes? As you could extend a single hash structure to "mark" the Best keys.
    the hardest line to type correctly is: stty erase ^H