How to sort hash by values in Perl?

Question

How to sort hash by values in Perl?

Sorting a hash by its values rather than its keys is a common question when working with Perl data structures. Hashes in Perl are inherently unordered collections of key-value pairs, meaning their internal order is not guaranteed. However, you can use the sort function and a custom comparison block to order the keys based on their corresponding values.

How to Sort a Hash by Values

You typically obtain a list of keys sorted according to their values. This involves passing a comparison block to sort, where you compare $hash{a} and $hash{b} (note the absence of sigils on a and b, which Perl special vars used inside sort blocks).

Here’s the general idiom:


my %hash = (apple => 2, orange => 5, banana => 1);

my @sorted_keys = sort { $hash{$a} <=> $hash{$b} } keys %hash;

This returns the keys sorted in ascending order of their values.

Explanation of the Example

  • %hash is a hash where keys are fruit names and values are numbers.
  • keys %hash returns a list of keys (unordered).
  • sort { $hash{$a} <=> $hash{$b} } keys %hash sorts them by comparing the values.
  • The operator <=> is the numeric comparison operator that returns -1, 0, or 1.

You can then iterate over the sorted keys and print the associated values.

Complete Runnable Example


use strict;
use warnings;

my %hash = (
    apple  => 2,
    orange => 5,
    banana => 1,
    pear   => 3,
);

# Sort keys by their corresponding values in ascending order
my @sorted_keys = sort { $hash{$a} <=> $hash{$b} } keys %hash;

# Print sorted keys and values
foreach my $key (@sorted_keys) {
    print "$key => $hash{$key}\n";
}

When you run this code (perl program.pl), the output will be:


banana => 1
apple => 2
pear => 3
orange => 5

Sorting in Descending Order

To sort in descending order by values, simply reverse the comparison:


my @sorted_desc = sort { $hash{$b} <=> $hash{$a} } keys %hash;

Considerations and Gotchas

  • Context: Sorting keys fetches a list, so you’re sorting a list of scalar strings, but using their associated hash values inside the block.
  • TMTOWTDI (“There’s More Than One Way To Do It”): You can also sort by string values using cmp instead of <=> if your values are non-numeric.
  • Non-existent keys: Make sure all keys exist in the hash to avoid warnings.
  • Numeric vs string comparison: Use <=> for numbers and cmp for strings.
  • Perl versions: This idiom works across all Perl 5 versions.

Example Using String Values


my %hash = (
    apple  => 'green',
    banana => 'yellow',
    cherry => 'red',
);

my @sorted_keys = sort { $hash{$a} cmp $hash{$b} } keys %hash;

foreach my $key (@sorted_keys) {
    print "$key => $hash{$key}\n";
}

This would sort keys by their string values alphabetically.

In summary, sorting a hash by values means sorting its keys using sort with value-based comparisons. This simple yet powerful approach leverages Perl’s flexible sorting and hash capabilities to arrange data as needed.

Verified Code

Executed in a sandbox to capture real output. • v5.34.1 • 6ms

Tip: edit code and use “Run (Browser)”. Server runs always execute the published, verified snippet.
STDOUT
(empty)
STDERR
(empty)

Was this helpful?

Related Questions