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