You don't need to make a list of the records. Just sort the keys according to the corresponding record values, like this:

my @sorted_keys = sort { extract( $hash{ $a } ) <=> extract( $hash{ $b } ) } keys %has +h; for my $key ( @sorted_keys ) { # whatever }
where extract is some function defined by you and that you apply to record values to get whatever you want the sorting to reflect. If extract returns strings that you want sorted alphabetically instead of numerically, then use cmp instead of <=>. And if you just want the sorting for the records to be plain ol' alphabetical sorting, then make that
my @sorted_keys = sort { $hash{ $a } cmp $hash{ $b } } keys %hash; for my $key ( @sorted_keys ) { # whatever }
Or you can optimize things further by using the Schwartzian Transform:
my @sorted_keys = map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [ $_, extract( $hash{ $_ } ) ] } keys %hash;
or any other sort optimization technique.

The important thing is that you are sorting the keys, even if the criterion for this sort is based on the associated values.

More generally, it is very common to want to sort a collection of items ($z, $y, $x, $w, ...) based on the values (f($z), f($y), f($x), f($w), ...) of some function f applied to those items. For example, if you want to sort strings without regard for their case, that function f could be uc (or equivalently lc). Then you just do

my @sorted = sort { f($a) cmp f($b) } @unsorted;
or
my @sorted = sort { f($a) <=> f($b) } @unsorted;
The important point is that what ends up in the @sorted arrays is not the f($z), f($y), f($x)... but the original $z, $y, $x,... (except that now they are sorted).

And the second important point is that "dereferencing a hash key" is in this case conceptually no different from applying some function to the keys. I.e. f for this case could be defined as

sub f { my $key = shift; return $hash{ $key }; }
Of course, a function f like the one above that does nothing to the hash value is usually not very useful, since we may as well just use $hash{ $key } directly.

the lowliest monk


In reply to Re: sorting a hash by tlm
in thread sorting a hash by Ben Win Lue

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.