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

Dear Monks,

I have a hash of hashes. The lower hash contains a number of values associated with indentical keys, which are shared across all lower hashes. However, across the higher hash keys, the composition of the lower hash keys can varry.

e.g.(lower hash keys)
Fruit : bannana
More_Fruit : peach
Even_more_Fruit : grape

Upper keys.
Downtown_Market : Fruit, More_Fruit, Even_more_Fruit
Uptown_market : More_fruit, Fruit
East_market : Even_more_fruit

I provide this to make the question make a bit more sense.
What I would like to do is get a print out of each key in a set order. So say print something like:

Downtown_market : (Fruit, More_fruit, Even_more_Fruit) Uptown_Market : (Fruit, More_fruit, ) East_Markey : ( , , Even_More_Fruit) #Note: Spaces are there for effect, to show I am skipping parts
Here is the code I have thus far, however the print bit is the hard part for me. I have read in the cookbook about printing in insertion order, but that is not what I want here. I want an order that I define. I am thinking a map function might work, but I can't figure out how to make that work.
use Data::Dumper; my %hash; my %hash_2; my %over_hash; my @array_1 = ('value'); #eg. grape. my @array_2 = ('value_2'); #eg. orange my @array_3 = ('value_3'); my @array_4 = ('value_4'); $hash{'key1'}=[@array_1]; #eg. Fruit $hash{'key2'}=[@array_2]; #eg. More_Fruit $hash{'key3'}=[@array_3]; $hash{'key4'}=[@array_4]; $hash_2{'key1'}=[@array_1]; $hash_2{'key2'}=[@array_2]; $hash_2{'key4'}=[@array_4]; $over_hash{'key1'} = [%hash]; #eg. Downtown_Market $over_hash{'key2'} = [%hash_2]; #eg. Uptown_market print Data::Dumper->Dumpxs([\%over_hash], [q{*over_hash}]); foreach my $unlocked (keys %over_hash) { my %internal_hash = @{$over_hash}{$unlocked}; foreach my $keys (keys %internal_hash) { my @print_value = @{$internal_hash{$keys}}; } print "@print_value\n"; } #order to print = (key1, key3, key4, key2); # how do I make the hash print in the order I want. # while leaving blanks for positions that are missing. #e.g. #overhash_key1 : key1 : key3 : key4, key2 #overhash_key2 : key1 : : key4, key2
As always I thank you for your time and help,
-Bio.
---- Even a blind squirrel finds a nut sometimes.

Replies are listed 'Best First'.
Re: Print from HoH, in defined order, skipping missing keys
by GrandFather (Saint) on May 30, 2008 at 03:36 UTC

    You need two passes, one to build a list of sub-keys, and a second to print the table. Consider:

    use strict; my %hash = ( Downtown_Market => {Fruit => 1, More_fruit => 2, Even_more_fruit = +> 3}, Uptown_market => {More_fruit => 4, Fruit => 5}, East_market => {Even_more_fruit => 6}, ); my %columnLookup; my @columns; my $maxKeyLen = 0; # Build list of sub-keys for my $key (keys %hash) { $maxKeyLen = length $key if length $key > $maxKeyLen; for my $subKey (keys %{$hash{$key}}) { next if exists $columnLookup{$subKey}; $columnLookup{$subKey} = @columns; push @columns, $subKey; } } # Print the table for my $key (sort keys %hash) { printf "%-*s (", $maxKeyLen + 2, "$key :"; print join ', ', map {exists $hash{$key}{$_} ? $_ : ' ' x length $_} @columns; print ")\n"; }

    Prints:

    Downtown_Market : (Even_more_fruit, More_fruit, Fruit) East_market : (Even_more_fruit, , ) Uptown_market : ( , More_fruit, Fruit)

    Perl is environmentally friendly - it saves trees