Python预置的list.sort()、sorted()方法可实现各种数组的排序,但支持的只限于一个key,如果要多重排序,目前所知的方法只有自定义了。
Help on built-in function sorted in module __builtin__:
sorted(...)
sorted(iterable, cmp=None, key=None, reverse=False) --> new sorted list
查看sorted的帮助可知,cmp参数在第二个位置,不过一般都以kwargs的形式显式写出。
关于cmp,cmp定义的函数接收源数组中相邻的两个元素,在比较大小后分别返回负值、0或正值,分别代表第一个值小于、等于或大于第二个值,然后再按照key和reverse的设定去进行排序。
>>> a=list(range(10)) >>> a.reverse() # reverse为on place方法 >>> a [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] >>> a.sort(cmp=lambda a,b: a-b) # a-b < 0 默认reverse为False,升顺排序,结果为正常顺序 >>> a [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> a.sort(cmp=lambda a,b: b-a) # b-a > 0 lambda返回正值,认为a > b,按照“升顺”排序,实际结果为降序 >>> a # sort同样是on place方法 [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] >>>
对于多重排序,可利用cmp方法,分别定义key的优先级,以及排序方式,达到多重、独立顺序的排序方式实现。
代码如下:
d1 = {1:23, 'b': 62} d2 = {1:24, 'b': 2} d3 = {1:23, 'b': 54} d4 = {1:23, 'b': 1} d5 = {1:01, 'b': 9} d6 = {1:23, 'b': 32} d7 = {1:05, 'b': 33} d8 = {1:39, 'b': 100} li = [d1, d2, d3, d4, d5, d6, d7, d8] def cmpf(a, b, key1, key2): if (a[key1] != b[key1]): return a[key1] - b[key1] else: return a[key2] - b[key2] def rcmpf(a, b, key1, key2): if (a[key1] != b[key1]): return b[key1] - a[key1] else: return a[key2] - b[key2] # key1、key2均为升序 sorted(li, cmp=lambda a,b: cmpf(a, b, 1, 'b')) # key1降序、key2升序 sorted(li, cmp=lambda a,b: rcmpf(a, b, 1, 'b'))
执行结果如下:
>>> sorted(li, cmp=lambda a,b: cmpf(a, b, 1, 'b')) [{1: 1, 'b': 9}, {1: 5, 'b': 33}, {1: 23, 'b': 1}, {1: 23, 'b': 32}, {1: 23, 'b': 54}, {1: 23, 'b': 62}, {1: 24, 'b': 2}, {1: 39, 'b': 100}] >>> >>> sorted(li, cmp=lambda a,b: rcmpf(a, b, 1, 'b')) [{1: 39, 'b': 100}, {1: 24, 'b': 2}, {1: 23, 'b': 1}, {1: 23, 'b': 32}, {1: 23, 'b': 54}, {1: 23, 'b': 62}, {1: 5, 'b': 33}, {1: 1, 'b': 9}] >>>
可以看到混合排序结果正常。
PS:按照预想,这种方式应该适用于所有可以指定多个key的数据结构,不过仍待验证。
对于Python3,sort方法取消了cmp参数,官方给出的解决方案是进行多次排序,优先级低的字段先排序,然后逐个根据优先级高的字段排序
>>> d1 = {1:23, 'b': 62} >>> d2 = {1:24, 'b': 2} >>> d3 = {1:23, 'b': 54} >>> d4 = {1:23, 'b': 1} >>> d5 = {1:1, 'b': 9} >>> d6 = {1:23, 'b': 32} >>> d7 = {1:5, 'b': 33} >>> d8 = {1:39, 'b': 100} >>> li = [d1, d2, d3, d4, d5, d6, d7, d8] >>> li.sort(key=lambda e: e['b']) # 现根据'b'进行排序,优先级较低 >>> pprint(li) [{1: 23, 'b': 1}, {1: 24, 'b': 2}, {1: 1, 'b': 9}, {1: 23, 'b': 32}, {1: 5, 'b': 33}, {1: 23, 'b': 54}, {1: 23, 'b': 62}, {1: 39, 'b': 100}] >>> li.sort(key=lambda e: e[1]) # 再根据1进行排序,优先级高于'b' >>> pprint(li) [{1: 1, 'b': 9}, {1: 5, 'b': 33}, {1: 23, 'b': 1}, {1: 23, 'b': 32}, {1: 23, 'b': 54}, {1: 23, 'b': 62}, {1: 24, 'b': 2}, {1: 39, 'b': 100}] >>>