Sorting a List by Computable Field
Problem
You want to sort a list by something more complex than a simple string or numeric comparison.
This is common when working with objects (“sort by the employee’s salary”) or complex data structures (“sort by the third element in the array that this is a reference to”). It’s also applicable when you want to sort by more than one key, for instance, sorting by birthday and then by name when multiple people have the same birthday.
Solution
Use the customizable comparison routine in sort:
@ordered = sort { compare() } @unordered;You can speed this up by precomputing the field.
@precomputed = map { [compute(),$_] } @unordered;
@ordered_precomputed = sort { $a->[0] <=> $b->[0] } @precomputed;
@ordered = map { $_->[1] } @ordered_precomputed;And, finally, you can combine the three steps:
@ordered = map { $_->[1] }
sort { $a->[0] <=> $b->[0] }
map { [compute(), $_] }
@unordered;Discussion
The use of a comparison routine was explained in Section 4.14. As well as using built-in operators like <=>, you can construct more complex tests:
@ordered = sort { $a->name cmp $b->name } @employees;You often see sort used like this in part of a
foreach loop:
foreach $employee (sort { $a->name cmp $b->name } @employees) {
print $employee->name, " earns \$", $employee->salary, "\n";
}If you’re going to do a lot of work with elements in a particular order, it’s more efficient to sort it once and work from that:
@sorted_employees = sort { $a->name cmp $b->name } @employees; ...Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access