Perl Sort函数用法总结和使用实例

一) sort函数用法

sort LIST
sort BLOCK LIST
sort SUBNAME LIST

sort的用法有如上3种形式。它对LIST进行排序,并返回排序后的列表。假如忽略了SUBNAME或BLOCK,sort按标准字串比较顺序来进行(例如ASCII顺序)。如果指定了SUBNAME,它实际上是个子函数的名字,该子函数对比2个列表元素,并返回一个小于,等于,或大于0的整数,这依赖于元素以何种顺序来sort(升序,恒等,或降序)。也可提供一个BLOCK作为匿名子函数来代替SUBNAME,效果是一样的。

被比较的2个元素,会被临时赋值给变量$a和$b。它们以引用传递,所以不要修改$a或$b。假如使用子函数,它不能是递归函数。

二) 用法实例

1. 以数字顺序sort    


代码如下:

@array = (8, 2, 32, 1, 4, 16);
print join(' ', sort {$a <=> $b} @array), "\n";

打印结果是:   


代码如下:

1 2 4 8 16 32

与之一样的是:


代码如下:

sub numerically { $a <=> $b };
print join(' ', sort numerically @array), "\n";

这个很容易理解哦,它只是按自然数的顺序进行sort,偶就不细讲了。

2.1 以ASCII顺序(非字典顺序)进行sort


代码如下:

@languages = qw(fortran lisp c c++ Perl python java);
print join(' ', sort @languages), "\n";

打印结果:


代码如下:

Perl c c++ fortran java lisp python

这等同于:


代码如下:

print join(' ', sort { $a cmp $b } @languages), "\n";

按ASCII的顺序进行排序,也没什么说的哦。

注意,如果对数字按ASCII顺序进行sort的话,结果可能与你想的不同:


代码如下:

print join(' ', sort 1 .. 11), "\n";
1 10 11 2 3 4 5 6 7 8 9

2.2 以字典顺序sort


代码如下:

use locale;
@array = qw(ASCII ascap at_large atlarge A ARP arp);
@sorted = sort { ($da = lc $a) =~ s/[/W_]+//g;
          ($db = lc $b) =~ s/[/W_]+//g;
          $da cmp $db;
          } @array;
print "@sorted\n";

打印结果是:  


代码如下:

A ARP arp ascap ASCII atlarge at_large

use locale是可选的--它让code兼容性更好,假如原始数据包含国际字符的话。use locale影响了cmp,lt,le,ge,gt和其他一些函数的操作属性--更多细节见perllocale的man page。

注意atlarge和at_large的顺序在输出时颠倒了,尽管它们的sort顺序是一样的(sort中间的子函数删掉了at_large中间的下划线)。这点会发生,是因为该示例运行在perl 5.005_02上。在perl版本5.6前,sort函数不会保护有一样values的keys的先后顺序。perl版本5.6和更高的版本,会保护这个顺序。

注意哦,不管是map,grep还是sort,都要保护这个临时变量$_(sort里是$a和$b)的值,不要去修改它
在该code里,在对$a或$b进行替换操作s/[/W_]+//g前,先将它们重新赋值给$da和$db,这样替换操作就不会修改原始元素哦。

3. 以降序sort

降序sort比较简单,把cmp或<=>前后的操作数调换下位置就可以了。


代码如下:

sort { $b <=> $a } @array;

或者改变中间的块或子函数的返回值的标记:


代码如下:

sort { -($a <=> $b) } @array;

或使用reverse函数(这有点低效,但也许易读点):


代码如下:

reverse sort { $a <=> $b } @array;

4. 使用多个keys进行sort

要以多个keys来sort,将所有以or连接起来的比较操作,放在一个子函数里即可。将主要的比较操作放在前面,次要的放在后面。


代码如下:

# An array of references to anonymous hashes
@employees = (
  { FIRST => 'Bill',   LAST => 'Gates',
    SALARY => 600000, AGE => 45 },
  { FIRST => 'George', LAST => 'Tester'
    SALARY => 55000, AGE => 29 },
  { FIRST => 'Steve', LAST => 'Ballmer',
    SALARY => 600000, AGE => 41 }
  { FIRST => 'Sally', LAST => 'Developer',
    SALARY => 55000, AGE => 29 },
  { FIRST => 'Joe',   LAST => 'Tester',
    SALARY => 55000, AGE => 29 },
);
sub seniority {
  $b->{SALARY}   <=> $a->{SALARY}
  or $b->{AGE}   <=> $a->{AGE}
  or $a->{LAST}   cmp $b->{LAST}
  or $a->{FIRST}   cmp $b->{FIRST}
}
@ranked = sort seniority @employees;
foreach $emp (@ranked) {
  print "$emp->{SALARY}/t$emp->{AGE}/t$emp->{FIRST}
    $emp->{LAST}\n";
}

打印结果是:


代码如下:

600000 45     Bill Gates
600000 41     Steve Ballmer
55000   29     Sally Developer
55000   29     George Tester
55000   29     Joe Tester

上述code看起来很复杂,实际上很容易理解哦。@employees数组的元素是匿名hash。匿名hash实际上是个引用,可使用->操作符来访问其值,例如$employees[0]->{SALARY}可访问到第一个匿名hash里SALARY对应的值。所以上述各项比较就很清楚了,先比较SALARY的值,再比较AGE的值,再比较LAST的值,最后比较FIRST的值。注意前2项比较是降序的,后2项是升序的,不要搞混了哦。

5. sort出新数组



代码如下:

@x = qw(matt elroy jane sally);
@rank[sort { $x[$a] cmp $x[$b] } 0 .. $#x] = 0 .. $#x;
print "@rank\n";

打印结果是:   


代码如下:

2 0 1 3

这里是否有点糊涂呀?仔细看就清楚了。0 .. $#x是个列表,它的值是@x数组的下标,这里就是0 1 2 3。$x[$a] cmp $x[$b] 就是将@x里的各个元素,按ASCII顺序进行比较。所以sort的结果返回对@x的下标进行排序的列表,排序的标准就是该下标对应的@x元素的ASCII顺序。
还不明白sort返回什么?让我们先打印出@x里元素的ASCII顺序:


代码如下:

@x = qw(matt elroy jane sally);
print join ' ',sort { $a cmp $b } @x;

打印结果是: 


代码如下:

elroy jane matt sally

它们在@x里对应的下标是1 2 0 3,所以上述sort返回的结果就是1 2 0 3这个列表了。@rank[1 2 0 3] = 0 .. $#x 只是个简单的数组赋值操作
所以@rank的结果就是(2 0 1 3)了。

6. 按keys对hash进行sort



代码如下:

%hash = (Donald => Knuth, Alan => Turing, John => Neumann);
@sorted = map { { ($_ => $hash{$_}) } } sort keys %hash;
foreach $hashref (@sorted) {
  ($key, $value) = each %$hashref;
  print "$key => $value\n";
}

打印结果是:


代码如下:

Alan => Turing
Donald => Knuth
John => Neumann

上述code不难明白哦。sort keys %hash按%hash的keys的ASCII顺序返回一个列表,然后用map进行计算,注意map这里用了双重{{}}
里面的 {} 是个匿名hash哦,也就是说map的结果是个匿名hash列表,明白了呀?
所以@sorted数组里的元素就是各个匿名hash,通过%$hashref进行反引用,就可以访问到它们的key/value值了。

7. 按values对hash进行sort



代码如下:

%hash = ( Elliot => Babbage,
      Charles => Babbage,
      Grace => Hopper,
      Herman => Hollerith
    );
@sorted = map { { ($_ => $hash{$_}) } }
        sort { $hash{$a} cmp $hash{$b}
              or $a cmp $b
            } keys %hash;
foreach $hashref (@sorted) {
  ($key, $value) = each %$hashref;
  print "$key => $value\n";
}

打印结果是:


代码如下:

Charles => Babbage
Elliot => Babbage
Herman => Hollerith
Grace => Hopper

与hash keys不同,我们不能保证hash values的唯一性。假如你仅根据values来sort hash,那么当你增或删其他values时,有着相同value的2个元素的sort顺序可能会改变。为了求得稳定的结果,应该对value进行主sort,对key进行从sort。

这里{ $hash{$a} cmp $hash{$b} or $a cmp $b } 就先按value再按key进行了2次sort哦,sort返回的结果是排序后的keys列表,然后这个列表再交给map进行计算,返回一个匿名hash列表。访问方法与前面的相同,偶就不详叙了。

8. 对文件里的单词进行sort,并去除重复的



代码如下:

perl -0777ane '$, = "\n"; @uniq{@F} = (); print sort keys %uniq' file

大家试试这种用法,我也不是很明白的说
@uniq{@F} = ()使用了hash slice来创建一个hash,它的keys是文件里的唯一单词;
该用法在语意上等同于$uniq{ $F[0], $F[1], ... $F[$#F] } = ()

各选项说明如下:


代码如下:

-0777   -   读入整个文件,而不是单行
-a     -   自动分割模式,将行分割到@F数组
-e     -   从命令行读取和运行脚本
-n     -   逐行遍历文件:while (<>) { ... }
$,     -   print函数的输出域分割符
file   -   文件名

9. 高效sorting: Orcish算法和Schwartzian转换

对每个key,sort的子函数通常被调用多次。假如非常在意sort运行时间,可使用Orcish算法或Schwartzian转换,以便每个key仅被计算1次
考虑如下示例,它根据文件修改日期来sort文件列表。

代码如下:

# 强迫算法--对每个文件要多次访问磁盘
@sorted = sort { -M $a <=> -M $b } @filenames;

# Orcish算法--在hash里创建keys
@sorted = sort { ($modtimes{$a} ||= -M $a) <=>
          ($modtimes{$b} ||= -M $b)
          } @filenames;

很巧妙的算法,是不是?因为文件的修改日期在脚本运行期间是基本不变的,所以-M运算一次后,把它存起来就可以了呀。
如下是Schwartzian转换的用法:

代码如下:

@sorted = map( { $_->[0] }
          sort( { $a->[1] <=> $b->[1] }
              map({ [$_, -M] } @filenames)
            )
        );

这个code结合用了map,sort分了好几层,记住偶以前提过的方法,从后往前看。map({ [$_, -M] } @filenames)返回一个列表,列表元素是匿名数组,匿名数组的第一个值是文件名,第二个值是文件的修改日期。

sort( { $a->[1] <=> $b->[1] }...再对上述产生的匿名数组列表进行sort,它根据文件的修改日期进行sort
sort返回的结果是经过排序后的匿名数组。

最外围的map( { $_->[0] }...就简单了,它从上述sort产生的匿名数组里提取出文件名。这个文件名就是根据修改日期进行sort过的呀,并且每个文件只运行了一次-M。
这就是著名的Schwartzian转换,这种用法在国外perl用户里很流行

(0)

相关推荐

  • PHP中的排序函数sort、asort、rsort、krsort、ksort区别分析

    sort() 函数用于对数组单元从低到高进行排序. rsort() 函数用于对数组单元从高到低进行排序. asort() 函数用于对数组单元从低到高进行排序并保持索引关系. arsort() 函数用于对数组单元从高到低进行排序并保持索引关系. ksort() 函数用于对数组单元按照键名从低到高进行排序. krsort() 函数用于对数组单元按照键名从高到低进行排序. sort() PHP sort() 函数用于对数组单元从低到高进行排序,如果成功则返回 TRUE,失败则返回 FALSE. 注意:

  • php数组排序usort、uksort与sort函数用法

    本文实例讲述了php数组排序usort.uksort与sort函数用法.分享给大家供大家参考.具体用法分析如下: 对数组排序:usort() 函数使用用户自定义的函数对数组排序,实例代码如下: 复制代码 代码如下: function cmp($a, $b)        //用户自定义回调函数 {   if($a==$b)         //如果两个参数相等   {     return 0;         //返回0   }   return($a>$b)?-1:1;       //如果

  • C++标准模板库函数sort的那些事儿

    STL里面有个sort函数,可以直接对数组排序,复杂度为n*log2(n).sort()定义在在头文件<algorithm>中.sort函数是标准模板库的函数,已知开始和结束的地址即可进行排序,可以用于比较任何容器(必须满足随机迭代器),任何元素,任何条件,执行速度一般比qsort要快.另外,sort()是类属函数,可以用于比较任何容器,任何元素,任何条件. 具体事例如下:char ch[20]="sdasdacsdasdas";cout<<ch<<

  • Lua的table库函数insert、remove、concat、sort详细介绍

    函数列表: table.insert(table,[ pos,] value) table.remove(table[, pos]) table.concat(table[, sep[, i[, j]]]) table.sort(table[, comp]) 1. insert 和 remove 只能用于数组元素的插入和移出, 进行插入和移出时,会将后面的元素对齐起来. 所以在 for 循环中进行 insert 和 remove 的时候要注意插入和移除时是否漏掉了某些项:   复制代码 代码如下

  • 浅析C/C++中sort函数的用法

    sort是STL中提供的算法,头文件为#include<algorithm>以及using namespace std; 函数原型如下: template <class RandomAccessIterator> void sort ( RandomAccessIterator first, RandomAccessIterator last ); template <class RandomAccessIterator, class Compare> void sor

  • PHP array_multisort() 函数的深入解析

    一.先看最简单的情况.有两个数组:$arr1 = array(1,9,5);$arr2 = array(6,2,4);array_multisort($arr1,$arr2);print_r($arr1); // 得到的顺序是1,5,9print_r($arr2); // 得到的顺序是6,4,2我估计两个数组的值自始至终都是对应着的:1对应6,9对应2,5对应4.我们再加多一个数组看看会怎样:$arr1 = array(1,9,5);$arr2 = array(6,2,4);$arr3 = ar

  • C语言中qsort函数用法实例小结

    本文实例汇总了C语言中qsort函数的常见用法,非常具有实用价值.分享给大家供大家参考.具体分析如下: C语言中的qsort函数包含在<stdlib.h>的头文件里,本文中排序都是采用的从小到大排序. 一.对int类型数组排序 int num[100]; int cmp ( const void *a , const void *b ) { return *(int *)a - *(int *)b; } qsort(num,100,sizeof(num[0]),cmp); 二.对char类型数

  • 详解Matlab中 sort 函数用法

    (1)B=sort(A) 对一维或二维数组进行升序排序,并返回排序后的数组,当A为二维时,对数组每一列进行排序. eg: A=[1,5,3],则sort(A)=[1,3,5] A=[1,5,3;2,4,1],则sort(A)=[1,4,1;2,5,3] (2)B=sort(A,dim),对数组按指定方向进行升序排序, dim =1,表示对每一列进行排序,,dim=2表示对每一行进行排序. (3)B=sort(A,dim,mode),mode为指定排序模式,mode为"ascend"时,

  • Perl Sort函数用法总结和使用实例

    一) sort函数用法 sort LISTsort BLOCK LISTsort SUBNAME LIST sort的用法有如上3种形式.它对LIST进行排序,并返回排序后的列表.假如忽略了SUBNAME或BLOCK,sort按标准字串比较顺序来进行(例如ASCII顺序).如果指定了SUBNAME,它实际上是个子函数的名字,该子函数对比2个列表元素,并返回一个小于,等于,或大于0的整数,这依赖于元素以何种顺序来sort(升序,恒等,或降序).也可提供一个BLOCK作为匿名子函数来代替SUBNAM

  • C#中Arraylist的sort函数用法实例分析

    本文实例讲述了C#中Arraylist的sort函数用法.分享给大家供大家参考.具体如下: ArrayList的sort函数有几种比较常用的重载: 1.不带参数 2.带一个参数 public virtual void Sort( IComparer comparer ) 参数 comparer 类型:System.Collections.IComparer 比较元素时要使用的 IComparer 实现. - 或 - null 引用(Visual Basic 中为 Nothing)将使用每个元数的

  • python中sort()函数用法详解

    目录 1.函数sort()是对列表就地排序 2.函数sort()修改序列,不返回任何值 3.sorted()函数会返回一个排序列表,不改变原有序列 4.函数sort()是升序排序,如何降序排序,需要用到函数reverse() 5.函数sort()排序的高级用法 (1) key参数 (2) reverse参数 补充:python中sort的用法——对列表中的元素按关键字排序 总结 1.函数sort()是对列表就地排序 >>> x=[8,9,0,7,4,5,1,2,3,6] >>

  • C++ sort排序函数用法详解

    目录 用法 两个参数用法 三个参数 string 使用反向迭代器来完成逆序排列 最近在刷ACM经常用到排序,以前老是写冒泡,可把冒泡带到OJ里后发现经常超时,所以本想用快排,可是很多学长推荐用sort函数,因为自己写的快排写不好真的没有sort快,所以毅然决然选择sort函数 用法 1.sort函数可以三个参数也可以两个参数,必须的头文件#include < algorithm>和using namespace std;2.它使用的排序方法是类似于快排的方法,时间复杂度为n*log2(n) 3

  • JS中sort函数排序用法实例分析

    本文实例讲述了JS中sort函数排序用法.分享给大家供大家参考,具体如下: 最近遇到了一个面试题目,关于排序的问题,为了完善自己的知识点,这里就写一下学习笔记 <html> <head> <TITLE>class_obj_js_class</TITLE> <script language=javaScript> //sort()方法默认是按照ASCII码大小排序,看下面两个例子 function sortDemo(){ var a, l; //

  • javascript中sort()的用法实例分析

    本文实例分析了javascript中sort()的用法.分享给大家供大家参考.具体分析如下: 函数的语法: arrayObject.sort(sortby) you think this is not the right way but you love it 这里还用到了split函数,目的是去到一个字符串的数组,比较常用.然后通过数组的排序函数sort()对数组内的值进行排序,得到新的数组,然后通过循环输出数组的内容就得到了排序后的字符串. 在例子中,默认情况下,它会按照ascii码来进行排

  • php Redis函数用法实例总结【附php连接redis单例类】

    本文实例总结了php Redis函数用法.分享给大家供大家参考,具体如下: 一直在拿PHP使用Redis,但是总感觉不牢靠,索性借这个时间空余一气呵成, 把PHP中所有操作到的Redis命令,几乎全敲个遍,包括它的返回值都是盯对过的,哪怕下回忘了也可以直接过来查嘛~大家也可以放心使用. 测试环境:    PHP:5.5     Redis:2.4.6 参考网址:   https://github.com/phpredis/phpredis Tips: 对于:string, set , sort

  • SeaJS中use函数用法实例分析

    本文实例讲述了SeaJS中use函数用法.分享给大家供大家参考,具体如下: 有了 define 等模块定义规范的实现,我们可以开发出很多模块.但光有一堆模块不管用,我们还得让它们能跑起来.在 SeaJS 里,要启动模块系统很简单: <script src="path/to/sea.js"></script> <script> seajs.use('./main'); </script> seajs.use 用来在页面中加载模块.通过 us

随机推荐