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
%hashis a hash where keys are fruit names and values are numbers.keys %hashreturns a list of keys (unordered).sort { $hash{$a} <=> $hash{$b} } keys %hashsorts 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
cmpinstead 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 andcmpfor 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
(empty)(empty)