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

Dear PerlMonks,

This is not as simple as the title suggest. The problem I have is that I have the below code:

#!c:\Perl\bin\perl use warnings; use strict; use diagnostics; use constant KANRI_01_0 => 0x00000001; # TBC use constant KANRI_01_1 => 0x00000002; # TBC use constant KANRI_02_0 => 0x00000004; # TBC use constant KANRI_02_1 => 0x00000008; # TBC use constant KANRI_03_0 => 0x00000010; # TBC use constant KANRI_04_1 => 0x00000020; # TBC use constant KANRI_04_2 => 0x00000040; # TBC use constant KANRI_04_3 => 0x00000080; # TBC use constant KANRI_04_4 => 0x00000100; # TBC use constant KANRI_05_1 => 0x00000200; # TBC use constant KANRI_05_2 => 0x00000400; # TBC use constant KANRI_06_1 => 0x00000800; # TBC use constant KANRI_07_1 => 0x00001000; # TBC use constant KANRI_07_2 => 0x00002000; # TBC use constant KANRI_07_3 => 0x00004000; # TBC use constant KANRI_07_4 => 0x00008000; # TBC use constant KANRI_07_5 => 0x00010000; # TBC use constant KANRI_08_1 => 0x00020000; # TBC my %menuHash = ( Outer1 => { O1Inne1 => KANRI_04_1, O1Inne2 => KANRI_04_2, O1Inne3 => KANRI_04_3, O1Inne4 => KANRI_04_4, } , Outer2 => { O2Inne1 => KANRI_05_1 }, Outer3 => { O3Inne1 => KANRI_06_1 }, Outer4 => { O4Inne1 => KANRI_07_1, O4Inne2 => KANRI_07_2, O4Inne3 => KANRI_07_3, O4Inne4 => KANRI_07_4, O4Inne5 => KANRI_07_5, }, Outer5 => { O5Inne1 => KANRI_08_1 }, ); for my $mainMenuItem ( keys %menuHash ) { print $mainMenuItem."\n"; for my $subMenuItem ( keys %{ $menuHash{$mainMenuItem} } ) { print "$subMenuItem = $menuHash{$mainMenuItem}{$subMenuIte +m} "; } print "\n"; }
This is all good and wonderful and the world turns as it should (well my code compiles and runs);

Now the problem I have is in the output. See I was expecting something like:

Outer1 01Inne1 = 32 01Inne2 = 64 01Inne3 = 128 01Inne4 = 256 Outer2 02Inne1 = 512 etc....
And if I got this it would be great... but I didn't. I got:
Outer4 O4Inne5 = 65536 O4Inne3 = 16384 O4Inne2 = 8192 O4Inne4 = 32768 + O4Inne1 = 4096 Outer2 O2Inne1 = 512 Outer1 O1Inne2 = 64 O1Inne4 = 256 O1Inne3 = 128 O1Inne1 = 32 Outer5 O5Inne1 = 131072 Outer3 O3Inne1 = 2048
Now I am running Strawberry Perl 5.12.1 on Windows XP, using the Eclipse EPIC IDE. I have ran this code from the CMD line, in Eclipse, and also through my web server as well. It all comes out like this.

What I am wanting to do is for it to print out the contents of the Hash of Hashes in the order they have been set up in. In this example the hash keys can be sorted, but in my actual code they can't (as they are alphanumerical and I don't want them sorted in that order), same with the values as well.

The reason for this structure is so that I can use this hash to print out two different levels of menu's (using CGI/HTML) and easily track the menu structure through this hash.

Would someone please be so kind as to point me in the direction of where I can find out what is causing this strange behavior (well it is strange from my POV).

I have searched on google for "problem with printing hashes", "printing order of hashes" and "sorting hashes" along with searching Perlmonks for "printing hashes", but have been unable to find anything on this particular problem. Only on using different sort methods.

Thank you in advance for taking the time at looking at this problem and for any suggestions you can offer. I will post the solution on this thread when I have one as well for others with a similar problem.

EDIT --- Link to the end solution I used

I have posted some dummy code similar to my end solution for printing a two layer HTML menu using constants as keys for hashes in this thread. This link will take you directly to the node.

Replies are listed 'Best First'.
Re: Problem with printing a Hash of Hashes in order
by GrandFather (Saint) on Jan 27, 2011 at 05:14 UTC

    Unless you use key based lookup for the data elsewhere you would probably be better to use a nested array structure instead of the nested hash structure you are currently using. Consider:

    #!c:\Perl\bin\perl use warnings; use strict; use constant KANRI_01_0 => 0x00000001; # TBC use constant KANRI_01_1 => 0x00000002; # TBC use constant KANRI_02_0 => 0x00000004; # TBC use constant KANRI_02_1 => 0x00000008; # TBC use constant KANRI_03_0 => 0x00000010; # TBC use constant KANRI_04_1 => 0x00000020; # TBC use constant KANRI_04_2 => 0x00000040; # TBC use constant KANRI_04_3 => 0x00000080; # TBC use constant KANRI_04_4 => 0x00000100; # TBC use constant KANRI_05_1 => 0x00000200; # TBC use constant KANRI_05_2 => 0x00000400; # TBC use constant KANRI_06_1 => 0x00000800; # TBC use constant KANRI_07_1 => 0x00001000; # TBC use constant KANRI_07_2 => 0x00002000; # TBC use constant KANRI_07_3 => 0x00004000; # TBC use constant KANRI_07_4 => 0x00008000; # TBC use constant KANRI_07_5 => 0x00010000; # TBC use constant KANRI_08_1 => 0x00020000; # TBC my @menu = ( [Outer1 => [ [O1Inne1 => KANRI_04_1], [O1Inne2 => KANRI_04_2], [O1Inne3 => KANRI_04_3], [O1Inne4 => KANRI_04_4], ]], [Outer2 => [[O2Inne1 => KANRI_05_1]]], [Outer3 => [[O3Inne1 => KANRI_06_1]]], [Outer4 => [ [O4Inne1 => KANRI_07_1], [O4Inne2 => KANRI_07_2], [O4Inne3 => KANRI_07_3], [O4Inne4 => KANRI_07_4], [O4Inne5 => KANRI_07_5], ]], [Outer5 => [[O5Inne1 => KANRI_08_1]]], ); for my $mainMenuItem (@menu) { print "$mainMenuItem->[0]\n"; for my $subMenuItem (@{$mainMenuItem->[1]}) { print "$subMenuItem->[0] = $subMenuItem->[1] "; } print "\n"; }

    Prints:

    Outer1 O1Inne1 = 32 O1Inne2 = 64 O1Inne3 = 128 O1Inne4 = 256 Outer2 O2Inne1 = 512 Outer3 O3Inne1 = 2048 Outer4 O4Inne1 = 4096 O4Inne2 = 8192 O4Inne3 = 16384 O4Inne4 = 32768 +O4Inne5 = 65536 Outer5 O5Inne1 = 131072
    True laziness is hard work

      I was thinking of basically the same thing, but with fewer square brackets thanks to some help from List::MoreUtils::natatime():

      >perl -wMstrict -le "use List::MoreUtils qw(natatime); ;; my @menuStruct = ( o1 => [ o1_i1 => 0x11, o1_i2 => 0x12, o1_i3 => 0x13, o1_i4 => 0x14, ], o2 => [ o2_i1 => 0x21 ], o3 => [ o3_i1 => 0x31 ], o4 => [ o4_i1 => 0x41, o4_i2 => 0x42, o4_i3 => 0x43, ], o5 => [ o5_i1 => 0x51 ], ); ;; my $o_iter = natatime 2, @menuStruct; while (my ($ok, $ov) = $o_iter->()) { print qq{$ok}; my $i_iter = natatime 2, @$ov; while (my ($ik, $iv) = $i_iter->()) { printf qq{ $ik = %x \n}, $iv; } } " o1 o1_i1 = 11 o1_i2 = 12 o1_i3 = 13 o1_i4 = 14 o2 o2_i1 = 21 o3 o3_i1 = 31 o4 o4_i1 = 41 o4_i2 = 42 o4_i3 = 43 o5 o5_i1 = 51

      I think either of these approaches could be made recursive.

Re: Problem with printing a Hash of Hashes in order
by toolic (Bishop) on Jan 27, 2011 at 03:39 UTC
    Would someone please be so kind as to point me in the direction of where I can find out what is causing this strange behavior (well it is strange from my POV).
    perldata states:
    Hashes are unordered collections of scalar values indexed by their associated string key.
    What I am wanting to do is for it to print out the contents of the Hash of Hashes in the order they have been set up in.
    At your command prompt, you can type:
    perldoc -q hash
    Which will eventually point you to Tie::IxHash:
    This Perl module implements Perl hashes that preserve the order in which the hash elements were added.
Re: Problem with printing a Hash of Hashes in order
by Khen1950fx (Canon) on Jan 27, 2011 at 09:21 UTC
    Try Tie::Hash::Sorted.
    #!perl use strict; use warnings; use diagnostics; use Tie::Hash::Sorted; use Data::Dumper::Concise; use constant KANRI_01_0 => 0x00000001; # TBC use constant KANRI_01_1 => 0x00000002; # TBC use constant KANRI_02_0 => 0x00000004; # TBC use constant KANRI_02_1 => 0x00000008; # TBC use constant KANRI_03_0 => 0x00000010; # TBC use constant KANRI_04_1 => 0x00000020; # TBC use constant KANRI_04_2 => 0x00000040; # TBC use constant KANRI_04_3 => 0x00000080; # TBC use constant KANRI_04_4 => 0x00000100; # TBC use constant KANRI_05_1 => 0x00000200; # TBC use constant KANRI_05_2 => 0x00000400; # TBC use constant KANRI_06_1 => 0x00000800; # TBC use constant KANRI_07_1 => 0x00001000; # TBC use constant KANRI_07_2 => 0x00002000; # TBC use constant KANRI_07_3 => 0x00004000; # TBC use constant KANRI_07_4 => 0x00008000; # TBC use constant KANRI_07_5 => 0x00010000; # TBC use constant KANRI_08_1 => 0x00020000; # TBC my %menu = ( Outer1 => { O1Inne1 => KANRI_04_1, O1Inne2 => KANRI_04_2, O1Inne3 => KANRI_04_3, O1Inne4 => KANRI_04_4, }, Outer2 => { O2Inne1 => KANRI_05_1 }, Outer3 => { O3Inne1 => KANRI_06_1 }, Outer4 => { O4Inne1 => KANRI_07_1, O4Inne2 => KANRI_07_2, O4Inne3 => KANRI_07_3, O4Inne4 => KANRI_07_4, O4Inne5 => KANRI_07_5, }, Outer5 => { O5Inne1 => KANRI_08_1 }, ); my $sort_by_numeric_value = sub { my $menu = shift; [ sort {$menu->{$a} <=> $menu->{$b}} keys %$menu ]; }; tie my %sorted_menu, 'Tie::Hash::Sorted', 'Hash' => \ %menu, 'Sort_Routine' => $sort_by_numeric_value; for my $key ( keys %sorted_menu ) { warn Dumper( $key, $sorted_menu{$key}); }
    Update: Here's a prettier-print:
    #!perl use strict; use warnings; use diagnostics; use Tie::Hash::Sorted; use YAML; use YAML::Dumper; use constant KANRI_01_0 => 0x00000001; # TBC use constant KANRI_01_1 => 0x00000002; # TBC use constant KANRI_02_0 => 0x00000004; # TBC use constant KANRI_02_1 => 0x00000008; # TBC use constant KANRI_03_0 => 0x00000010; # TBC use constant KANRI_04_1 => 0x00000020; # TBC use constant KANRI_04_2 => 0x00000040; # TBC use constant KANRI_04_3 => 0x00000080; # TBC use constant KANRI_04_4 => 0x00000100; # TBC use constant KANRI_05_1 => 0x00000200; # TBC use constant KANRI_05_2 => 0x00000400; # TBC use constant KANRI_06_1 => 0x00000800; # TBC use constant KANRI_07_1 => 0x00001000; # TBC use constant KANRI_07_2 => 0x00002000; # TBC use constant KANRI_07_3 => 0x00004000; # TBC use constant KANRI_07_4 => 0x00008000; # TBC use constant KANRI_07_5 => 0x00010000; # TBC use constant KANRI_08_1 => 0x00020000; # TBC my %menu = ( Outer1 => { O1Inne1 => KANRI_04_1, O1Inne2 => KANRI_04_2, O1Inne3 => KANRI_04_3, O1Inne4 => KANRI_04_4, }, Outer2 => { O2Inne1 => KANRI_05_1 }, Outer3 => { O3Inne1 => KANRI_06_1 }, Outer4 => { O4Inne1 => KANRI_07_1, O4Inne2 => KANRI_07_2, O4Inne3 => KANRI_07_3, O4Inne4 => KANRI_07_4, O4Inne5 => KANRI_07_5, }, Outer5 => { O5Inne1 => KANRI_08_1 }, ); my $sort_by_numeric_value = sub { my $menu = shift; [ sort {$menu->{$a} <=> $menu->{$b}} keys %$menu ]; }; my $dumper = YAML::Dumper->new; $dumper->indent_width(1); tie my %sorted_menu, 'Tie::Hash::Sorted', 'Hash' => \ %menu, 'Sort_Routine' => $sort_by_numeric_value; for my $key ( keys %sorted_menu ) { print $dumper->dump( {ascending_values => [$key, $sorted_menu{$key}]}); }

      Khen1950fx,

      If I am not mistaken, this would only sort by alphanumeric is this correct? Thank you for this, however the actual implementation I am looking at can not be sorted alphanumeric as this is not the order I want them to appear.

      But once again thank you for your reply.

      Regards,
      KyussRyn

Re: Problem with printing a Hash of Hashes in order
by KyussRyn (Acolyte) on Jan 27, 2011 at 06:55 UTC

    As I want to continue to use Keys for this, even though I think that the nested array structure will work just as well, I came up with the solution below using the suggestions from this thread here.

    #!c:\Perl\bin\perl use warnings; use strict; use diagnostics; use Tie::IxHash; use constant KANRI_01_0 => 0x00000001; use constant KANRI_01_1 => 0x00000002; use constant KANRI_02_0 => 0x00000004; use constant KANRI_02_1 => 0x00000008; use constant KANRI_03_0 => 0x00000010; use constant KANRI_04_1 => 0x00000020; use constant KANRI_04_2 => 0x00000040; use constant KANRI_04_3 => 0x00000080; use constant KANRI_04_4 => 0x00000100; use constant KANRI_05_1 => 0x00000200; use constant KANRI_05_2 => 0x00000400; use constant KANRI_06_1 => 0x00000800; use constant KANRI_07_1 => 0x00001000; use constant KANRI_07_2 => 0x00002000; use constant KANRI_07_3 => 0x00004000; use constant KANRI_07_4 => 0x00008000; use constant KANRI_07_5 => 0x00010000; use constant KANRI_08_1 => 0x00020000; sub ordered_hash_ref { tie my %hash, 'Tie::IxHash', @_; return \%hash; } tie my %menuHash, 'Tie::IxHash', Outer1 => ordered_hash_ref( O1Inne +1 => KANRI_04_1, O1Inne2 => KANRI_04_2, O1Inne3 => KANRI_04_3, O1Inne4 => KANRI_04_4, ) , Outer2 => ordered_hash_ref( O2Inne1 => KANRI_05_1 ), Outer3 => ordered_hash_ref( O3Inne1 => KANRI_06_1 ), Outer4 => ordered_hash_ref( O4Inne1 => KANRI_07_1, O4Inne2 => KANRI_07_2, O4Inne3 => KANRI_07_3, O4Inne4 => KANRI_07_4, O4Inne5 => KANRI_07_5, ), Outer5 => ordered_hash_ref( O5Inne1 => KANRI_08_1 ), ; for my $mainMenuItem ( keys %menuHash ) { print $mainMenuItem."\n"; for my $subMenuItem ( keys %{ $menuHash{$mainMenuItem} } ) { print "$subMenuItem = $menuHash{$mainMenuItem}{$subMenuIte +m} "; } print "\n"; }

    This provided the following output.

    Outer1 O1Inne1 = 32 O1Inne2 = 64 O1Inne3 = 128 O1Inne4 = 256 Outer2 O2Inne1 = 512 Outer3 O3Inne1 = 2048 Outer4 O4Inne1 = 4096 O4Inne2 = 8192 O4Inne3 = 16384 O4Inne4 = 32768 +O4Inne5 = 65536 Outer5 O5Inne1 = 131072
    After reading the Tie::IxHash help, then doing an online search using the keyword "preserving", helped me find other resources. I hope that this post helps others and thank you to Granfather and Toolic for your replies to my request for help.
Re: Problem with printing a Hash of Hashes in order
by KyussRyn (Acolyte) on Jan 28, 2011 at 02:28 UTC

    To help other beginner perl programmers, for the final use of this program, I ended up using a hash that used constants as the Keys as well.

    This caused me some more stress as Constants don't really work well with what I was planning to do. How I solved this was to move the constants to a seperate file (this was going to be the original plan as I have a seperate perl module in my project that holds all of the constants).

    For easy reference for programmers who are looking at using this method for making a HTML menu (or other uses here is the dummy final code I created:

    #!c:\Perl\bin\perl use warnings; use strict; use diagnostics; use CGI ':standard'; use CGI::Carp qw(fatalsToBrowser); use Tie::IxHash; use CONSTANTS; tie my %menuHash, 'Tie::IxHash',CONSTANTS::TOP_MENU1_ => ordered_ha +sh_ref( CONSTANTS::TM1_SUB1_ => CONSTANTS::KANRI_SCREEN_04_1, CONSTANTS::TM1_SUB2_ => CONSTANTS::KANRI_SCREEN_04_2, CONSTANTS::TM1_SUB3_ => CONSTANTS::KANRI_SCREEN_04_3, CONSTANTS::TM1_SUB4_ => CONSTANTS::KANRI_SCREEN_04_4 ), CONSTANTS::TOP_MENU2_ => ordered_hash_ref( CONSTANTS::TM2_SUB1_ + => CONSTANTS::KANRI_SCREEN_05_1 ), CONSTANTS::TOP_MENU3_ => ordered_hash_ref( CONSTANTS::TM3_SUB1_ + => CONSTANTS::KANRI_SCREEN_06_1 ), CONSTANTS::TOP_MENU4_ => ordered_hash_ref( CONSTANTS::TM4_SUB1_ + => CONSTANTS::KANRI_SCREEN_07_1, CONSTANTS::TM4_SUB2_ => CONSTANTS::KANRI_SCREEN_07_2, CONSTANTS::TM4_SUB3_ => CONSTANTS::KANRI_SCREEN_07_3, CONSTANTS::TM4_SUB4_ => CONSTANTS::KANRI_SCREEN_07_4, CONSTANTS::TM4_SUB5_ => CONSTANTS::KANRI_SCREEN_07_5 ), CONSTANTS::TOP_MENU5_ => ordered_hash_ref( CONSTANTS::TM5_SUB1_ + => CONSTANTS::KANRI_SCREEN_08_1 ); my $cgi = new CGI; sub PrintMenu { my $upperMenu = shift; print "<hr>\n"; print $cgi->start_table( { -width => '100%', -border => 0 }); print "\n"; print '<tr align="center">'."\n"; for my $mainMenuItem ( keys %menuHash ) { print "<th>"; print $mainMenuItem; print "</th>\n"; } print "</tr>\n"; print $cgi->end_table(); print "<hr>\n"; print $cgi->start_table( { -width => '100%', -border => 0 }); print '<tr align="center">'."\n"; for my $subMenuItem ( keys %{ $menuHash{$upperMenu} } ) { print "<th>"; print $cgi->a( {-href => $menuHash{$upperMenu}{$subMenuItem +}, -target => '_self' }, "$subMenuItem" ); print "</th>\n"; } print "</tr>\n"; print $cgi->end_table(); print "\n"; print "<hr>\n"; } PrintMenu( CONSTANTS::TOP_MENU1_ );

    And the code for the CONSTANTS.pm file is:

    #!c:\Perl\bin\perl use warnings; use strict; package CONSTANTS; use constant { TOP_MENU1_ => 'TopMenu1', TOP_MENU2_ => 'TopMenu2', TOP_MENU3_ => 'TopMenu3', TOP_MENU4_ => 'TopMenu4', TOP_MENU5_ => 'TopMenu5', TM1_SUB1_ => 'SubMenu11', TM1_SUB2_ => 'SubMenu12', TM1_SUB3_ => 'SubMenu13', TM1_SUB4_ => 'SubMenu14', TM2_SUB1_ => 'SubMenu21', TM3_SUB1_ => 'SubMenu31', TM4_SUB1_ => 'SubMenu41', TM4_SUB2_ => 'SubMenu42', TM4_SUB3_ => 'SubMenu43', TM4_SUB4_ => 'SubMenu44', TM4_SUB5_ => 'SubMenu45', TM5_SUB1_ => 'SubMenu51', };

    I hope this is helpful to people who read this with the same questions I had.