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

I have a multi-dimensional hash that needs to be sorted numerically. The hash stores names, head count, and house type. $HoH{$name}{'house_type'} $HoH{$name}{'head_count'}
(%HoH) = ( "Smith" => { "house_type" => 'colonial', "head_count" => '5', }, "Jones" => { "house_type" => 'cape', "head_count" => '3', }, );
I would like to print this out, sorted by the head_count:
Smith House Type: colonial Head Count: 5
Jones House Type: cape Head Count: 3

I'm having difficulty with finding a solution for this. Please help!

Replies are listed 'Best First'.
Re: Sort Hash of Hash numerically
by toolic (Bishop) on Jun 13, 2011 at 14:22 UTC
    Super Search where title contains all of "sort", "hash", "of":
    use warnings; use strict; my (%HoH) = ( "Smith" => { "house_type" => 'colonial', "head_count" => '5', }, "Jones" => { "house_type" => 'cape', "head_count" => '3', }, ); for (reverse sort { $HoH{$a}{head_count} <=> $HoH{$b}{head_count} } ke +ys %HoH) { print "$_ House Type: $HoH{$_}{house_type} Head Count: $HoH{$_}{he +ad_count}\n"; } __END__ Smith House Type: colonial Head Count: 5 Jones House Type: cape Head Count: 3

      Is reverse sort optimized away (it would be cool if it swapped the meaning of $a and $b) or do you really mean:

      for (sort { $HoH{$b}{head_count} <=> $HoH{$a}{head_count} } keys %HoH) + { print "$_ House Type: $HoH{$_}{house_type} Head Count: $HoH{$_}{he +ad_count}\n"; }

      Update: toolic++. I went searching for the definition of "newer perls" and found that this optimization has been around for some time. From perl586delta:

      reverse sort ... is now optimized to sort in reverse, avoiding the generation of a temporary intermediate list.

      for (reverse @foo) now iterates in reverse, avoiding the generation of a temporary reversed list.

      Good Day,
          Dean

        I really meant to use reverse. According to Perl::Critic::Policy::BuiltinFunctions::ProhibitReverseSortBlock
        Conway says that it is much clearer to use reverse than to flip $a and $b around in a sort block. He also suggests that, in newer perls, reverse is specifically looked for and optimized, and in the case of a simple reversed string sort, using reverse with a sort with no block is faster even in old perls.
      Awesome, that did it. Thanks!
Re: Sort Hash of Hash numerically
by zek152 (Pilgrim) on Jun 13, 2011 at 14:36 UTC

    Basically you have to store the data in a temporary hash. Keep the family name with the subhash and sort the array by the head count.

    #insert HoH here @temp_array = (); for $i (keys(%HoH)) { #the name must be kept with the subhash. $HoH{$i}{"name"} = $i; push @temp_array, $HoH{$i}; #updated:transposition error on my part } #sort the temp array by decreasing head counts @temp_array = sort {$$b{"head_count"} <=> $$a{"head_count"}} @temp_arr +ay; for $i (@temp_array) { print "$$i{'name'} House Type: $$i{'house_type'} Head Count $$i{'h +ead_count'}\n"; }

    Updated: error in my code.

      for $i (keys(%HoH)) { #the name must be kept with the subhash. $HoH{$i}{"name"} = $i; push @temp_array, $HoH }

      In the above for loop, the statement
          push @temp_array, $HoH
      would appear to need to be
          push @temp_array, $HoH{$i};
      to work (or to compile with strictures).