sortSUBNAME
LIST
sortBLOCK
LIST
sortLIST
This function sorts the LIST
and returns the sorted
list value. By default, it sorts in standard string comparison order (undefined
values sorting before defined null strings, which sort before everything else).
SUBNAME
, if given, is the name of a subroutine that
returns an integer less than, equal to, or greater than 0, depending on how the
elements of the list are to be ordered. (The handy <=>
and cmp
operators can be used to perform three-way numeric
and string comparisons.) In the interests of efficiency, the normal calling
code for subroutines is bypassed, with the following effects: the subroutine may
not be a recursive subroutine, and the two elements to be compared are passed
into the subroutine not via @_
but as $a and $b (see the examples
below). The variables $a and $b are passed by reference, so don't modify them in the
subroutine. SUBNAME
may be a scalar variable name
(unsubscripted), in which case the value provides the name of (or a reference
to) the actual subroutine to use. In place of a
SUBNAME
, you can provide a
BLOCK
as an anonymous, in-line sort subroutine.
To do an ordinary numeric sort, say this:
sub numerically { $a <=> $b; } @sortedbynumber = sort numerically 53,29,11,32,7;
To sort in descending order, simply reverse the $a
and $b
. To sort a list value by some associated value, use a hash
lookup in the sort routine:
sub byage { $age{$a} <=> $age{$b}; } @sortedclass = sort byage @class;
As an extension of that notion, you can cascade several different
comparisons using the handy comparison operators, which work nicely for
this because when they return 0
they fall through to the next
case. The routine below sorts to the front of the list those people who are
first richer, then taller, then younger, then less alphabetically
challenged. We also put a final comparison between $a
and
$b
to make sure the ordering is always well defined.
sub prospects { $money{$b} <=> $money{$a} or $height{$b} <=> $height{$a} or $age{$a} <=> $age{$b} or $lastname{$a} cmp $lastname{$b} or $a cmp $b; } @sortedclass = sort prospects @class;
To sort fields without regard to case, say:
@sorted = sort { lc($a) cmp lc($b) } @unsorted;
And finally, note the equivalence of the two ways to sort in reverse:
sub backwards { $b cmp $a; } @harry = qw(dog cat x Cain Abel); @george = qw(gone chased yz Punished Axed); print sort @harry; # prints AbelCaincatdogx print sort backwards @harry; # prints xdogcatCainAbel print reverse sort @harry; # prints xdogcatCainAbel print sort @george, "to", @harry; # Remember, it's one LIST. # prints AbelAxedCainPunishedcatchaseddoggonetoxyz
Do not declare $a and $b as lexical
variables (with my). They are package
globals (though they're exempt from the usual restrictions on globals when
you're using use strict
). You do need to make sure your sort
routine is in the same package though, or qualify $a
and
$b
with the package name of the caller.
One last caveat. Perl's sort is implemented in terms of C's qsort(3) function. Some qsort(3) versions will dump core if your sort subroutine provides inconsistent ordering of values.