while ( my ($test,$val) = each %{$sorter->()} ) calls &$sorter every time through the loop. That meeans that &$sorter creates a new hash and sorts it every time through the loop. It also means you keep calling each on a new hash every time. None of that is good. Also, you want the keys, but you discard them by using values.

The trick is to sort the keys (by value, if so desired) into an array, and loop over that array.

my @ordered_keys; if ($sort eq 't') { # Calculate the order in which we want to process %tests. # (Sort keys by ascending numerical Total.) @ordered_keys = sort { $tests{$a}{Total} <=> $tests{$b}{Total} } keys %tests; } elsif ($sort eq 'v') { # Calculate the order in which we want to process %tests. # (Sort keys by ascending numerical Value.) @ordered_keys = sort { $tests{$a}{Value} <=> $tests{$b}{Value} } keys %tests; } foreach my $key (@ordered_keys) { my $val = $tests{$key}; print "$key\n"; print " Total: $val->{Total}\n"; print " Value: $val->{Value}\n\n"; }

By the way, you were sorting alphabetically. Now, it's sorting numerically.

By the way, when dumping a hash or an array, pass a reference to the variable to Dumper (e.g. print Dumper \%tests;) for better results.

Update: The only purpose of using a sub would be to delay the calculation of @ordered_keys. If that's what you wish to do, what follows is a transformation of the above which postpones the calculation of @ordered_keys by use of a sub:

my $sorter; if ($sort eq 't') { # Sort keys by ascending numerical Total. $sorter = sub { my ($tests) = @_; return sort { $tests->{$a}{Total} <=> $tests->{$b}{Total} } keys %$tests; }; } elsif ($sort eq 'v') { # Sort keys by ascending numerical Value. $sorter = sub { my ($tests) = @_; return sort { $tests->{$a}{Value} <=> $tests->{$b}{Value} } keys %$tests; }; } foreach my $key ($sorter->(\%tests)) { my $val = $tests{$key}; print "$key\n"; print " Total: $val->{Total}\n"; print " Value: $val->{Value}\n\n"; }

foreach will build the list over which it iterates only once, so it doesn't suffer the same problem as your while solution.


In reply to Re: Sorting a hash of a hash using anonymous subs by ikegami
in thread Sorting a hash of a hash using anonymous subs by madbombX

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.