Lists

sort#

Sort a list, returning the sorted list.

sort takes a list and returns a new list with the elements rearranged in order. With no comparator it uses standard string comparison. With a BLOCK or a SUBNAME you supply the comparison rule as a small function that is called for each pair of elements and must return a negative, zero, or positive value the way cmp and <=> do.

Sorting is stable — elements that compare equal keep their original relative order. The algorithm is mergesort.

Synopsis#

sort LIST
sort BLOCK LIST
sort SUBNAME LIST

Three idiomatic forms:

my @out = sort @in;                        # default: string cmp, ascending
my @out = sort { $a <=> $b } @in;          # numeric, ascending
my @out = sort by_name @in;                # named comparator sub

What you get back#

A new sorted list. sort does not modify the input in place. To replace an array with its sorted version you assign back:

@a = sort @a;

In list context the return is the sorted list. In scalar context the return value is undefined — do not use scalar sort.

The returned list contains aliases into the original list, exactly like a foreach index variable. Modifying an element of the result inside a later foreach, map, or grep therefore modifies the original element too. This is almost never what you want; treat the result as read-only.

Global state: $a and $b#

Inside the comparator BLOCK or SUBNAME, the two elements being compared are exposed as the package globals $a and $b. These are not parameters and they are not lexicals — they are real package variables that sort localises for you around the call.

  • $a and $b live in the package that called sort. In main, that is $main::a and $main::b; in Foo, $Foo::a and $Foo::b.

  • Never declare my $a or my $b anywhere the sort block can see. A lexical $a or $b shadows the package global; the block then compares two unrelated variables and the sort silently produces garbage. Under use warnings you get no warning for this.

  • If you genuinely need $a / $b as lexicals elsewhere, refer to the sort variables by full name inside the block:

    print sort { $::a cmp $::b }         qw(A C E G B D F H);
    print sort { our $a cmp our $b }     qw(A C E G B D F H);
    
  • A comparator defined with the prototype ($$) (or an equivalent signature attribute) receives the pair in @_ instead of $a and $b. This is slower than the $a/$b convention but decouples the sub from the caller’s package.

Both elements are passed by reference; mutating $a or $b in the block mutates the original list. Don’t.

Examples#

Default string sort:

my @sorted = sort qw(banana apple cherry);
# ('apple', 'banana', 'cherry')

Numeric ascending — the default sort @nums would sort "10" before "2" because comparison is by string:

my @nums = sort { $a <=> $b } (10, 2, 33, 4);
# (2, 4, 10, 33)

Numeric descending — swap $a and $b:

my @nums = sort { $b <=> $a } (10, 2, 33, 4);
# (33, 10, 4, 2)

Multi-key sort with a tiebreaker. || runs the second comparator only when the first returns 0:

my @people = sort {
    $a->{last}  cmp $b->{last}
 || $a->{first} cmp $b->{first}
} @records;

Sort a hash’s keys by the associated value:

my %age = (alice => 30, bob => 25, carol => 40);
my @by_age = sort { $age{$a} <=> $age{$b} } keys %age;
# ('bob', 'alice', 'carol')

Schwartzian Transform — when the sort key is expensive to compute, precompute it once per element, sort the [key, value] pairs, then strip the keys. Three stages, read bottom-up:

my @sorted =
    map  { $_->[1] }                     # 3. strip key
    sort { $a->[0] <=> $b->[0] }         # 2. sort by key
    map  { [ expensive_key($_), $_ ] }   # 1. attach key
    @input;

Named comparator sub. The sub reads $a and $b from the caller’s package, so it must be in (or referenced from) that package:

sub by_name { $a->{name} cmp $b->{name} }

my @sorted = sort by_name @people;

Prototyped comparator — arguments arrive in @_, so it works from any package:

sub numeric ($$) { $_[0] <=> $_[1] }

my @sorted = sort numeric @nums;

Edge cases#

  • $a and $b are package globals, not lexicals. A stray my $a in scope silently breaks every sort in that scope. If you must, use our $a or $::a inside the block.

  • <=> is numeric, cmp is string. Using the wrong one is the most common sort bug. sort { $a cmp $b } (10, 2, 33) yields (10, 2, 33) — lexicographic, "10" before "2". Use <=> for numbers.

  • Empty list returns an empty list. sort () is (). No error.

  • Single element is returned unchanged. No comparisons happen.

  • Comparator must be consistent. If it sometimes says $x < $y and sometimes says the opposite for the same pair, the result is undefined. The comparator must return a total ordering: negative, zero, or positive, stably, for every call.

  • NaN poisons <=>. $a <=> $b returns undef if either operand is NaN, which sort then treats as 0 — equal — giving an arbitrary placement. Filter first:

    my @clean = sort { $a <=> $b } grep { $_ == $_ } @input;
    
  • Stable sort. Equal elements keep their input order. Rely on this for multi-pass sorts (sort by secondary key first, then by primary key). use sort 'stable' is the default and a no-op; use sort '_mergesort' / '_qsort' pragmas are historical and have no effect on current Perl.

  • sort is not in-place. sort @a does not touch @a. Use @a = sort @a to replace it. Assigning to sort’s result list aliases back into the original, so (sort @a)[0] = ... modifies @a’s smallest element.

  • No loop control out of the block. last, next, redo, return, and goto LABEL do not work inside a sort comparator — the block is not a loop body.

  • Parser trap: sorting a function’s return value. sort takes a LIST, so a following bareword can be mistaken for a SUBNAME. To sort the result of find_records(@key):

    my @out = sort { $a cmp $b } find_records @key;   # OK
    my @out = sort +find_records(@key);               # OK
    my @out = sort(find_records(@key));               # OK
    

    To use find_records as the comparator over @key instead:

    my @out = sort find_records @key;                 # comparator form
    my @out = sort { find_records() } @key;           # block form
    
  • Locale-aware sorting. Under use locale (without ':not_characters') the default string comparison follows the current collation locale instead of codepoint order.

  • XSUB comparators. If the comparator is an XSUB, the pair is passed on the argument stack the way XS functions normally receive arguments; $a and $b are not set.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • reverse — reverses a list; combine with sort for descending sorts when the comparator is hard to invert by swapping $a and $b

  • map — the other half of the Schwartzian Transform; use to attach and strip sort keys around a sort

  • grep — prefilter the list (e.g. remove NaN or undef) before handing it to sort

  • $a — the first element in the comparison pair, aliased as a package global for the duration of the sort

  • $b — the second element in the comparison pair, same lifetime and scoping rules as $a

  • <=> — numeric three-way comparison; the usual operator inside a numeric sort block

  • cmp — string three-way comparison; the usual operator inside a string sort block