http://www.perlmonks.org?node_id=654433

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

What is the best way to sort the hash by value and printing out the top 5 results? For array, I guess you can do something like
@count_s = sort { $reportn{$a} <=> $reportn{$b}; } @count_s; foreach (@count_s[0..4]) { print "$_ ====> $reportn{$_}\n"; }
But not sure about hash as below method does not work.
is it just my grammar mistake?
foreach my $hero ( sort keys %total_o) { if ($reportn_o{$hero}) { @reportnL = sort { $total_o{$a} <=> $total_o{$b} } values (%t +otal_o{$hero}); } } for (@reportnL[0..4]) { print "$_\n"; }

Replies are listed 'Best First'.
Re: sort hash by value
by salva (Canon) on Dec 02, 2007 at 19:55 UTC
    Sorting the full list of items to get just the top n is not the most efficient way, there are better algorithms. See Selection_algorithm.

    You can also use Sort::Key::Top instead of implementing those algorithms yourself ;-)

Re: sort hash by value
by moritz (Cardinal) on Dec 02, 2007 at 18:01 UTC
    Since you can't reverse a hash in the general case, you can just make a list of lists:
    my @list = map { [$_, $hash{$_}] } keys %hash; # sort it: @list = sort { $a->[1] cmp $b->[1] }; # now you can print it
Re: sort hash by value
by grep (Monsignor) on Dec 02, 2007 at 18:11 UTC
    I'm not quite sure what your doing with all that code, there seem to be quite a few mistakes. Which makes it hard for me to follow.

    But as to your main point of the sort not working: You're sending in the values but treating them like keys and trying to do a lookup.
    @reportnL = sort { $total_o{$a} <=> $total_o{$b} } values (%total_o{$hero});

    Change it to
    @reportnL = sort { $total_o{$a} <=> $total_o{$b} } keys %total_o ;

    UPDATE: Just noticed his was my 500th post.

    grep
    One dead unjugged rabbit fish later...
Re: sort hash by value
by johngg (Canon) on Dec 02, 2007 at 18:44 UTC
    for (@reportnL[0..4]) { print "$_\n"; }

    Your use of an array slice here seems a little unusual, not incorrect but not the way I suspect most would approach the task. I would perhaps do

    for ( 0 .. 4 ) { print qq{$reportnL[$_]\n}; }

    or, more probably

    print qq{$reportnL[$_]\n} for 0 .. 4;

    I hope this is of interest.

    Cheers,

    JohnGG