Sort and the Schwartzian transform

Contents
Default sort
Numbers need a block
Sort by a field
Sort a hash by value
The Schwartzian transform

Default sort

sort with no block compares elements as strings, using the cmp operator. That is what you want for names and paths, and wrong for numbers.

my @names = qw(grace ada linus); my @sorted = sort @names; print "@sorted\n"; # ada grace linus

perl demo.pl

ada grace linus

sort returns a new list and leaves the original alone, which is one more reason to keep it inside an expression. To sort in place, assign the result back to the same array.

Numbers need a block

As strings, 10 comes before 9. Give sort a block that compares with the spaceship operator and the numbers line up.

my @nums = (10, 9, 100); print join(" ", sort @nums), "\n"; # 10 100 9 print join(" ", sort { $a <=> $b } @nums), "\n"; # 9 10 100

perl demo.pl

10 100 9
9 10 100

Inside the block the two values being compared are $a and $b, package variables that sort fills in. Swap them for a descending order: $b <=> $a.

Sort by a field

For records, the block compares the field that matters. A tie-breaker in the same block keeps equal values in a stable order instead of an arbitrary one.

my @users = ( { name => "Ada", age => 36 }, { name => "Grace", age => 45 }, { name => "Alan", age => 41 }, ); my @by_age = sort { $a->{age} <=> $b->{age} } @users; print join(", ", map { $_->{name} } @by_age), "\n"; # Ada, Alan, Grace

perl demo.pl

Ada, Alan, Grace

Sort a hash by value

Hashes have no order, but keys can be sorted by their values. The classic form sorts keys and reads the hash inside the block.

my %hits = (index => 10, about => 2, blog => 7); my @top = sort { $hits{$b} <=> $hits{$a} } keys %hits; print "@top\n"; # index blog about

perl demo.pl

index blog about

Comparing $b with $a reverses the order, so the biggest number comes first. The same trick sorts any hash by any numeric value.

The Schwartzian transform

A sort block runs many times, so an expensive key function is called again and again. Build each key once, sort the pairs, then throw the keys away. The idiom is named after Randal Schwartz.

my @files = qw(b.log a.txt c.md); my @by_ext = map { $_->[0] } sort { $a->[1] cmp $b->[1] } map { [ $_, ($_ =~ /\.(\w+)$/)[0] ] } @files; print "@by_ext\n"; # b.log c.md a.txt

perl demo.pl

b.log c.md a.txt

Read it from the bottom: map builds pairs, sort compares the second slot, map takes the first slot back. For plain string sorts the extra machinery is not worth it, so use it only when the key is expensive.

Next: Read and write files

Article author: Arthur Isaev

Related articles
Perl
Perl course: zero to hero in 50 lessons
What is Perl and where it runs
Install Perl and check the version
Your first Perl script
The debugger as a REPL
Scalars and sigils
Numbers
Strings
Interpolation and quoting
Arrays
push, pop, shift and splice
Hashes
keys, values, exists and delete
Scalar and list context
Conditions and comparison
while, for, next and last
foreach and the default variable
Subroutines
Arguments in @_
References
Nested data structures
Regular expressions: match and anchors
Captures and named groups
Substitution with s///
split and join
grep and map
Sort and the Schwartzian transform
Read and write files
File tests and metadata
Directories and paths
die, warn and eval
Modules and Exporter
CPAN and cpanm
Objects with bless
Modern objects with Moo
Testing with Test::More
strict, warnings and diagnostics
Options with Getopt::Long
Environment and %ENV
system, backticks and pipes
One-liners with -n and -p
CSV and TSV processing
JSON with JSON::PP
HTTP clients with HTTP::Tiny
Sockets and IO::Socket
Databases with DBI
Capstone: todo CLI
Capstone: log report
Performance and profiling
Modern Perl tour
Hero roadmap: the whole course on one page
Install Perl on Windows 11
Install Perl on Ubuntu
Install Perl on Rocky Linux
Install Perl on macOS
Install Perl on FreeBSD
Perl in Docker

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: