sort 也可指模块:sort
sort SUBNAME LIST
sort BLOCK LIST
sort LIST

在列表上下文中,这会对 LIST 进行排序并返回排序后的列表值。在标量上下文中,sort 的行为未定义。

如果省略 SUBNAME 或 BLOCK,sort 会按照标准字符串比较顺序进行排序。如果指定了 SUBNAME,它会提供一个子例程的名称,该子例程返回小于、等于或大于 0 的数值,具体取决于列表元素的排序方式。(<=>cmp 运算符在这些例程中非常有用。)SUBNAME 可以是标量变量名称(无下标),在这种情况下,该值提供要使用的实际子例程的名称(或引用)。您可以提供一个 BLOCK 作为匿名内联排序子例程,来代替 SUBNAME。

如果子例程的原型是 ($$),要比较的元素将通过引用传递给 @_,就像普通子例程一样。这比未编制原型的子例程慢,在未编制原型的子例程中,要比较的元素作为包全局变量 $a$b 传递到子例程中(请参见下面的示例)。

如果子例程是 XSUB,则要比较的元素将推送到堆栈上,这是通常将参数传递给 XSUB 的方式。$a$b 未设置。

要比较的值总是通过引用传递,不应修改。

您也不能使用 perlsyn 中描述的任何循环控制运算符或使用 goto 退出排序块或子例程。

use locale(但不是 use locale ':not_characters')生效时,sort LIST 会根据当前的排序规则对 LIST 进行排序。请参见 perllocale

sort 返回原始列表中的别名,就像 for 循环的索引变量对列表元素进行别名一样。也就是说,修改 sort 返回的列表的元素(例如,在 foreachmapgrep 中)实际上会修改原始列表中的元素。在编写清晰的代码时,通常应避免这样做。

历史上,Perl 在默认情况下排序是否稳定方面有所不同。如果稳定性很重要,可以使用 sort 实用程序显式控制它。

示例

# sort lexically
my @articles = sort @files;

# same thing, but with explicit sort routine
my @articles = sort {$a cmp $b} @files;

# now case-insensitively
my @articles = sort {fc($a) cmp fc($b)} @files;

# same thing in reversed order
my @articles = sort {$b cmp $a} @files;

# sort numerically ascending
my @articles = sort {$a <=> $b} @files;

# sort numerically descending
my @articles = sort {$b <=> $a} @files;

# this sorts the %age hash by value instead of key
# using an in-line function
my @eldest = sort { $age{$b} <=> $age{$a} } keys %age;

# sort using explicit subroutine name
sub byage {
    $age{$a} <=> $age{$b};  # presuming numeric
}
my @sortedclass = sort byage @class;

sub backwards { $b cmp $a }
my @harry  = qw(dog cat x Cain Abel);
my @george = qw(gone chased yz Punished Axed);
print sort @harry;
    # prints AbelCaincatdogx
print sort backwards @harry;
    # prints xdogcatCainAbel
print sort @george, 'to', @harry;
    # prints AbelAxedCainPunishedcatchaseddoggonetoxyz

# inefficiently sort by descending numeric compare using
# the first integer after the first = sign, or the
# whole record case-insensitively otherwise

my @new = sort {
    ($b =~ /=(\d+)/)[0] <=> ($a =~ /=(\d+)/)[0]
                        ||
                fc($a)  cmp  fc($b)
} @old;

# same thing, but much more efficiently;
# we'll build auxiliary indices instead
# for speed
my (@nums, @caps);
for (@old) {
    push @nums, ( /=(\d+)/ ? $1 : undef );
    push @caps, fc($_);
}

my @new = @old[ sort {
                       $nums[$b] <=> $nums[$a]
                                ||
                       $caps[$a] cmp $caps[$b]
                     } 0..$#old
              ];

# same thing, but without any temps
my @new = map { $_->[0] }
       sort { $b->[1] <=> $a->[1]
                       ||
              $a->[2] cmp $b->[2]
       } map { [$_, /=(\d+)/, fc($_)] } @old;

# using a prototype allows you to use any comparison subroutine
# as a sort subroutine (including other package's subroutines)
package Other;
sub backwards ($$) { $_[1] cmp $_[0]; }  # $a and $b are
                                         # not set here
package main;
my @new = sort Other::backwards @old;

## using a prototype with function signature
use feature 'signatures';
sub function_with_signature :prototype($$) ($one, $two) {
    return $one <=> $two
}

my @new = sort function_with_signature @old;

# guarantee stability
use sort 'stable';
my @new = sort { substr($a, 3, 5) cmp substr($b, 3, 5) } @old;

警告:对从函数返回的列表进行排序时需要语法上的注意。如果您想对函数调用 find_records(@key) 返回的列表进行排序,可以使用

my @contact = sort { $a cmp $b } find_records @key;
my @contact = sort +find_records(@key);
my @contact = sort &find_records(@key);
my @contact = sort(find_records(@key));

如果您想使用比较例程 find_records() 对数组 @key 进行排序,则可以使用

my @contact = sort { find_records() } @key;
my @contact = sort find_records(@key);
my @contact = sort(find_records @key);
my @contact = sort(find_records (@key));

$a$b 在调用 sort() 的包中设置为包全局变量。这意味着在 main 包中为 $main::a$main::b(或 $::a$::b),在 FooPack 包中为 $FooPack::a$FooPack::b,依此类推。如果排序块在 $a 和/或 $bmystate 声明的范围内,则必须在排序块中写出变量的完整名称

package main;
my $a = "C"; # DANGER, Will Robinson, DANGER !!!

print sort { $a cmp $b }               qw(A C E G B D F H);
                                       # WRONG
sub badlexi { $a cmp $b }
print sort badlexi                     qw(A C E G B D F H);
                                       # WRONG
# the above prints BACFEDGH or some other incorrect ordering

print sort { $::a cmp $::b }           qw(A C E G B D F H);
                                       # OK
print sort { our $a cmp our $b }       qw(A C E G B D F H);
                                       # also OK
print sort { our ($a, $b); $a cmp $b } qw(A C E G B D F H);
                                       # also OK
sub lexi { our $a cmp our $b }
print sort lexi                        qw(A C E G B D F H);
                                       # also OK
# the above print ABCDEFGH

通过适当的注意,您可以混合包和 my(或 state)$a 和/或 $b

my $a = {
   tiny   => -2,
   small  => -1,
   normal => 0,
   big    => 1,
   huge   => 2
};

say sort { $a->{our $a} <=> $a->{our $b} }
    qw{ huge normal tiny small big};

# prints tinysmallnormalbighuge

$a$b 隐式地对 sort() 执行本地化,并在完成排序后恢复其以前的值。

使用 $a$b 编写的排序子例程绑定到其调用包。在不同的包中定义它们是可能的,但兴趣有限,因为子例程仍然必须引用调用包的 $a$b

package Foo;
sub lexi { $Bar::a cmp $Bar::b }
package Bar;
... sort Foo::lexi ...

使用编制原型的版本(见上文)作为更通用的替代方案。

比较函数需要表现良好。如果它返回不一致的结果(例如,有时说 $x[1] 小于 $x[2],有时又说相反),则结果未定义。

因为当任一操作数为 NaN(非数字)时,<=> 返回 undef,因此在使用比较函数(如 $a <=> $b)对可能包含 NaN 的任何列表进行排序时要小心。以下示例利用 NaN != NaN 来消除输入列表中的任何 NaN

my @result = sort { $a <=> $b } grep { $_ == $_ } @input;

在此版本的 perl 中,sort 函数是通过归并排序算法实现的。