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