Perl内置sort以ASCII码序对列表排序.Perl允许建立自己的排序规则子程序,或简称排序子程序来实现想要的排序方式.
这里的排序子程序不是数据结构中的冒泡排序,希尔排序等,Perl知道怎么对列表排序,只是不知道要用什么样的规则,所以排序子程序只是用来说明具体的规则.
排序子程序并不需要比较许多元素,只要能比较两个元素就行.
- #!/usr/bin/perl
-
use strict;
-
use5.010;
-
sub any_sort_sub {
-
my($a,$b)=@_;
-
......
-
}
实际上这么写不能正确工作,这里只是为了方便说明问题.子程序内声明了两个变量并给它们赋值,然后开始比较$a和$b.
排序子程序会一次次地被调用,往往运行很多次,在子程序开始的地方声明变量$a和$b并给它们赋值,看起来只会花一点时间,但是把这些时间乘以排序子程序可能被调用的次数,就可以看出,这对整体性能会造成不小的影响.
实际写排序子程序并不会这么做.在子程序开始之前,Perl已经办好了这些事情.实际写出的排序子程序并不会有例子中的第5行,$a和$b都已经被自动赋值好了.当排序子程序开始运行时,$a和$b会是两个来自原始列表的元素(顺序什么的不需要考虑了).
假如在结果列表中$a应该在$b之前,排序子程序就会返回-1;如果$b应该在$a之前,它就会返回1;如果$a与$b的先后不必区分,则返回0.
飞碟操作符(<=>)
- #!/usr/bin/perl
-
use strict;
-
use 5.010;
-
sub by_number {
-
if($a<$b) {
-
return-1;
-
}elsif($a>$b) {
-
return1;
-
}else{
-
return0;
-
}
-
}
-
my @org=qw(12 4 5 7 3 9 6);
-
my @cur=sort by_number @org;
-
say "@cur";
程序为了让数字从小到大排序,实现了子程序by_number.
程序的第5行刀第11行,根据Perl排序子程序的工作规则来看:
如果$a<$b,则$a在$b之前.
如果$a>$b,则$a在$b之后.
如果$a==$b,则位置不动.
这样写在Perl看来太麻烦了,所以有更加简便的写法:
- #!/usr/bin/perl
-
use strict;
-
use 5.010;
-
sub by_number {
-
$a<=>$b;
-
}
-
my @org=qw(12 4 5 7 3 9 6);
-
my @cur=sort by_number @org;
-
say "@cur";
程序中第5行完全能代替前面程序第5~11行的功能.
也就是说,飞碟操作符(<=>)的功能就是让Perl知道,$a在什么情况下会排在$b的前面.
$a<=>$b表示:$a较小时,$a在$b之前.
$b<=>$a表示:$b较小时,$a在$b之前.
$a<$b时,表达式返回-1.($a在前面)
$a=$b时,表达式返回0.
$a>$b时,表达式返回1.($a在后面).
所以表达式是按递增排序.
同理来读 $b<=>$a,会知道是按递减排序.
飞碟操作符(<=>)专门用来处理数字,在Perl中还有个与飞碟操作符的逻辑完全一样,专门用来处理字符串的操作符:cmp
如果排序规则很简单,就不需要把规则独立写成一个子程序,可以内嵌到排序语句中:
- #!/usr/bin/perl
-
use strict;
-
use 5.010;
-
my @org=qw(12 4 5 7 3 9 6);
-
my @cur=sort {$a<=>$b} @org;
-
say "@cur";
按多值排序
假设有一个哈希,key为人名,value为每人的分数.现在要把哈希按分数从小到大排序,如果分数一样,则按名字的ASCII顺序排.
- #!/usr/bin/perl
-
use strict;
-
use 5.010;
-
my %score=("barney"=>195,
-
"fred"=>205,
-
"dino"=>30,
-
"john"=>67,
-
"ada"=>30,
-
);
程序的第11,12行实现了按多值排序.
多值排序基于两个概念实现:
- Perl任务0为FALSE,非0为TRUE.
- 逻辑表达式具有短路特性.
在Perl的排序子程序中,$a==$b时会返回0,所以如果分数相等,第11行表达式返回0,在逻辑表达式中Perl认为是FALSE.需要执行第12行来确定整个表达式的值.如果分数不相等,第11行表达式的值为1/-1,Perl认为是TRUE,不需要判断or之后表达式的值了.这就实现了按多值排序.
子程序by_value中的or可以根据实际情况写很多个.
阅读(364) | 评论(0) | 转发(0) |