关于Python的多重排序

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}]
>>> 

 

posted @ 2015-11-03 21:17  harelion  阅读(8525)  评论(0编辑  收藏  举报