Perl Sorting Guide — Custom Comparisons, Stable Sort, and Advanced Techniques
In this tutorial, you will learn about Perl Sorting Guide. We cover key concepts, practical examples, and best practices to help you master this topic.
Perl sort function takes a comparison block with $a and $b package variables, using cmp for string comparison and <=> for numeric comparison -- with the Schwartzian transform for sorting by expensive computed values and GRT (Guttman-Rosler Transform) for maximum speed.
Basic Sort
my @numbers = (5, 3, 8, 1, 9, 2);
my @strings = qw(banana apple cherry date);
# Default sort (string comparison)
my @sorted = sort @numbers; # (1, 2, 3, 5, 8, 9) - strings!
# Numeric sort
my @numeric = sort { $a <=> $b } @numbers; # (1, 2, 3, 5, 8, 9)
# Reverse sort
my @desc = sort { $b <=> $a } @numbers; # (9, 8, 5, 3, 2, 1)
Custom Comparisons
# Sort by string length
my @words = qw(long longer longest short);
my @by_length = sort { length($a) <=> length($b) } @words;
# Sort by multiple criteria
my @people = (
{ name => "Alice", age => 30 },
{ name => "Bob", age => 25 },
{ name => "Alice", age => 20 },
);
my @sorted = sort {
$a->{name} cmp $b->{name} # first by name
||
$a->{age} <=> $b->{age} # then by age
} @people;
Case-Insensitive Sort
my @mixed = qw(Apple banana Cherry date);
# Case-insensitive
my @sorted = sort { lc($a) cmp lc($b) } @mixed;
# Using fc (fold case, Unicode-safe, Perl 5.16+)
use feature 'fc';
my @sorted2 = sort { fc($a) cmp fc($b) } @mixed;
Schwartzian Transform
# Without transform (computes length for each comparison)
my @sorted = sort { length($a) <=> length($b) } @words;
# With Schwartzian transform (compute once, cache)
my @sorted = map { $_->[0] }
sort { $a->[1] <=> $b->[1] }
map { [$_, length($_)] }
@words;
# Step by step:
# 1. map: wrap each word with [word, length]
# 2. sort: compare by cached length
# 3. map: extract original words
Sort on Hash Values
my %score = (
Alice => 95,
Bob => 87,
Carol => 92,
);
# Sort keys by value (ascending)
my @by_score = sort { $score{$a} <=> $score{$b} } keys %score;
# Sort keys by value (descending)
my @top = sort { $score{$b} <=> $score{$a} } keys %score;
# Sort by value, then by key
my @sorted = sort {
$score{$b} <=> $score{$a} # high scores first
||
$a cmp $b # alphabetical tie-breaker
} keys %score;
Common Mistakes
1. Forgetting $a and $b are package variables
$a and $b are global in the comparison block. Don't declare them with my.
2. Using == instead of <=> or cmp
== tests equality (returns true/false). <=> returns -1, 0, or 1. Use <=> for numeric sort.
3. Modifying $a or $b in the comparison
The sort comparison should be a pure function. Side effects break the sort algorithm.
Practice Questions
1. How do you sort numbers numerically?
sort { $a <=> $b } @numbers. The default sort compares as strings.
2. What is the Schwartzian transform? A technique that precomputes sort keys in a map-sort-map chain to avoid recomputing expensive comparisons.
3. How do you sort a hash by values?
sort { $hash{$a} cmp $hash{$b} } keys %hash for strings, or <=> for numbers.
FAQ
{{< faq question="Is Perl's sort stable?" >}} No. Perl's sort is not guaranteed stable (equal elements may not preserve original order). {{< /faq >}}
{{< faq question="What is the GRT (Guttman-Rosler Transform)?" >}}
An optimization that packs sort keys into a single string for ultra-fast sorting: my @sorted = map { substr($_, 4) } sort map { pack("N", length) . $_ } @data.
{{< /faq >}}
{{< faq question="Can I sort in place?" >}}
sort returns a new list. To sort in place, assign back: @array = sort @array.
{{< /faq >}}
What's Next
Now learn about map and grep for list processing.
| Topic | Description | Link |
|---|---|---|
| Map/Grep | List transformation and filtering | {{< ref "20-maps-filters" >}} |
| DBI | Database interface | {{< ref "21-dbi" >}} |
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro