Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1572526
  • 博文数量: 289
  • 博客积分: 11086
  • 博客等级: 上将
  • 技术积分: 3291
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-22 17:06
个人简介

徐小玉的博客。

文章分类

全部博文(289)

文章存档

2023年(6)

2022年(1)

2021年(2)

2020年(9)

2019年(9)

2018年(6)

2017年(10)

2016年(10)

2014年(3)

2013年(4)

2011年(12)

2010年(16)

2009年(14)

2008年(119)

2007年(48)

2006年(20)

我的朋友

分类:

2008-05-23 12:23:25

Perl的排序

Perl好用的原因之一在于它的灵活性,这一点来源于很多小的好处。其中排序功能是很常用的:
my %hashNames = { '1' => 'Sharon Basque-Dion',
'2' => 'Dave Schuman',
'3' => 'Sally Waltson',
'0x10' => 'Rodney Wiederman',
'0x1F' => 'Angus O'Hare',
'0x2A' => 'Jean-Pascal Conteau' };
要对上面关联数组里的值进行排序,可以用sort:
foreach my $szName (sort values %hashNames){
print $szName;
}

当然反向排序也是有的,用reverse sort
foreach my $szName (reverse sort values %hashNames){
print $szName;
}
Perl缺省的sort是区分大小写的ASCII码排序。如果需要其它排序方式,例如不分大小写的字母排序怎么办?

当进入sort情景时,Perl提供两个全局变量,分别叫$a和$b,指向待比较的两个值。注意不要去改变它们的值,我试着改过,结果就是得到的结果面目全非。在sort关键词的后面,可以跟一个用于比较的函数名或者一段用花括号括起来的代码。另外,Perl提供比较两个操作符,一个是cmp(比较操作符), $a cmp $b的结果是$a和$b按ASCII顺序排序得到的结果1,0,-1(大,等于,小)。另外一个是<=>(星船操作符,starship operator),$a <=> $b返回$a和$b按数值大小比较的结果1,0,-1(代表大,等于,小)。确省情况下,sort是等同于sort { $a cmp $b}的,Perl是利用归并(merge)算法和ASCII比较来排序。更详细的语法说明见。

假如我们需要按字典顺序对人名进行排序,可以写一个自己的排序函数,其中利用到$a, $b, cmp或者<=>。其实最后的返回值只要符合1,0,-1的定义就可以。

sub by_dictionary_sequence{
my $aa = lc $a; #得到小写形式
my $bb = lc $b;
$aa =~ s/[\W_]+//g; #去掉非字典字符
$aa =~ s/[\W_]+//g;
$aa cmp $bb;
}

foreach my $szName (sort by_dictionary_sequence values %hashNames){
print $szName;
}

我习惯使用by_...作为比较函数的名字,这样跟在sort后面正好是一句话。Perl会使用sort后跟的函数来进行元素的两两比较,代替缺省的{ $a cmp $b}。要使用字典降序排列的话,只要把dictionary_sequence的最后一句里的$aa和$bb换个位置就行。事实上系统提供了$a和$b以及sort后可跟函数的功能以后,如何进行比较就已经不是 Perl语言本身要关注的内容了。例如前面的%hashNames,我们看到它的键是10进制和16进制数的混合,可以这样来排序:
sub by_mix_numeric{
my $aa = $a;
my $bb = $b;
$aa = $1 if($aa =~ /0x(.*)/);
$bb = $1 if($bb =~ /0x(.*)/);
$aa = hex( $aa); $bb = hex($bb);
$aa <=> $bb;
}

foreach my $szIndex (sort by_mix_numeric keys %hashNames){
print $szIndex ;
}

更多见的一个例子是数据库排序,先按最重要列排序,如果相等则再看次重要列等等,这基本是体力活,虽然说数据库排序也还是很有技巧的,比如Orcish算法,Schwartzian转换和Guttman-Rosler转换(GRT)等等,那已经超出我的兴趣范围了,详细内容可以看 。 如果真需要用,我可能会考虑CPAN上的Sort::Fields模块。

最后要罗嗦一句的是,如果不想给自己找烦恼的话,永远都不要自定义变量$a和$b。也许这就是为什么C#向Perl学习了foreach结构却的原因:C#的框架里没有这样的缺省变量的位置。

阅读(2662) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~