搜尋

首頁  >  問答  >  主體

Python3 sorted函数中key参数的作用原理

这是一个字符串排序,排序规则:小写<大写<奇数<偶数

s = 'asdf234GDSdsf23'  #排序:小写-大写-奇数-偶数
print("".join(sorted(s, key=lambda x: (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))))

这里key接受的函数返回的是一个元组?是如何进行比较的?

高洛峰高洛峰2823 天前1492

全部回覆(3)我來回復

  • 伊谢尔伦

    伊谢尔伦2017-04-17 17:49:14

    先比較元組的第一個值,FALSE

    回覆
    0
  • PHP中文网

    PHP中文网2017-04-17 17:49:14

    讓我們從一個簡單的例子開始:

    items = [(1, 2), (2, 1)]
    print(sorted(items))
    

    結果:

    [(1, 2), (2, 1)]
    

    items 是一個list of tuple,如果針對tuple 排序,Python 的Builtin function sorted(或sort) 會從tuple的最後一個元素開始進行排序,也就是說一組二元素的tuple 進行排序可以想像成兩次基本的排序:items 是一個 list of tuple,如果針對 tuple 排序,Python 的 Builtin function sorted(或是sort) 會從 tuple 的最後一個元素開始進行排序,也就是說一組二元素的 tuple 進行排序可以想像成兩次基本的排序:

    原本是:

    [(2, 1), (1, 2)]
    

    第一次排序以第2個元素為 key,所以排序的結果為:

    [(2, 1), (1, 2)]
    

    第二次排序以第1個元素為 key,所以排序的結果為:

    [(1, 2), (2, 1)] # 最終結果
    

    結論(1):

    tuple 的排序由最後的元素往前依次進行排序
    也就是說 tuple 的排序權重是由第一個元素開始依次向後遞減


    接著我們來觀察一下 Boolean value 的排序:

    print(sorted([True, False])
    

    結果:

    [False, True] # False在前,True在後
    

    結論2

    Boolean 的排序會將 False 排在前,True排在後


    那我們來看看你給出的例子,我們撰寫一個簡單的 function 來觀察結果:

    def show(s):
        for x in s:
            print((x.isdigit(), x.isdigit() and int(x)%2==0, x.isupper(), x.islower(), x))
    

    function show 會列印出當下的字串 s 用來排序時每個字元所產生的 tuple key.

    接著我們套用剛剛的結論1,我們先不使用 tuple 來作為 key,反而利用等價的 由最後一個元素往前依次為 key 排序,並且逐步觀察 s 和 tuple key 的變化:

    print('key=x')
    s = sorted(s ,key=lambda x: x)
    show(s)
    
    print('key=islower()')
    s = sorted(s ,key=lambda x: x.islower())
    show(s)
    
    print('key=isupper()')
    s = sorted(s ,key=lambda x: x.isupper())
    show(s)
    
    print('key=isdigit() and int(x)%2==0')
    s = sorted(s ,key=lambda x: x.isdigit() and int(x)%2==0)
    show(s)
    

    我們將會發現一如預期地,依照結論(1),這樣的做法的確等價於一口氣以 tuple 為 key 來排序.
    同時觀察,結論(2),對於 isdigit(), isupper(), islower()

    原本是:
    print('key=isdigit()')
    s = sorted(s ,key=lambda x: x.isdigit())
    show(s)
    

    第一次排序以第2個元素為 key,所以排序的結果為:

    sorted(s, key=lambda x: (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))
    
    第二次排序以第1個元素為 key,所以排序的結果為:

    print("".join(sorted(s1, key=lambda x: (not x.islower(), not x.isupper(), not(x.isdigit() and int(x)%2==1), x))))
    

    結論(1)
    :

    tuple 的排序由最後的元素往前依次進行排序
    也就是說 tuple 的排序權重是由第一個元素開始依次向後遞減

    接著我們來觀察 Boolean value 的排序:
    rrreee

    結果:

    rrreee

    結論2

    Boolean 的排序會將 False 排在前,True排在後

    那我們來看看你給的例子,我們寫一個簡單的 function 來觀察結果:

    rrreee

    function show 會印出當下的字串 s 用來排序時每個字元所產生的 tuple key. #🎜🎜# #🎜🎜#接著我們套用剛剛的結論1,我們先不使用tuple 來作為key,反而利用等價的#🎜🎜#由最後一個元素往前依次為key 排序#🎜🎜#,並且逐步觀察s 和tuple key 的變化:#🎜🎜# rrreee #🎜🎜#我們將會發現一如預期地,依照結論(1),這樣的做法的確等價於一口氣以 tuple 為 key 來排序.
    同時觀察,結論(2),對於isdigit(), isupper(), islower()等產生的Boolean key來說,排序的結果也如預期. #🎜🎜# rrreee #🎜🎜# #🎜🎜#不過我想這還不是我們最後的結論,因為這是一個碰巧的結果(說碰巧也許太超過了,應該說是不那麼直覺的結果),讓我們根據#🎜🎜#結論(1 )#🎜🎜# 對最初的例子進行分析:#🎜🎜# rrreee #🎜🎜#這個排序我們可以翻譯成:#🎜🎜# #🎜🎜##🎜🎜#先對字符x本身做排序,接著是對 字符是否為小寫,字符是否為大寫,字符是否為偶數,字符是否為數字分別作排序. #🎜🎜##🎜🎜# #🎜🎜#也可以翻譯成:#🎜🎜# #🎜🎜##🎜🎜#我們以 字符是否為數字為最高排序權重,接著以字符是否為偶數,字符是否為大寫,字符是否為小寫,字符x本身為權重來做排序. #🎜🎜##🎜🎜# #🎜🎜#這似乎與一開始的目標(#排序:小寫-大寫-奇數-偶數)不同,起碼跟目標沒有直覺上的對應. #🎜🎜# #🎜🎜#建議可以改成:#🎜🎜# rrreee #🎜🎜#這樣就可以解讀為:#🎜🎜# #🎜🎜##🎜🎜#我們以 字符是否為小寫為最高權重,接著以字符是否為大寫,字符是否為奇數,字符x本身為權重來做排序#🎜🎜#

    有趣的是:我們想要讓判斷式為 True 的字元在排序完成後在比較前面的位置,所以根據結論(2)加了一個 not來讓符合的字符可以在前面.

    回覆
    0
  • 高洛峰

    高洛峰2017-04-17 17:49:14

    關鍵之處如donghui所說,FALSEdonghui所说,FALSE<TRUE。
    key为元组的排序情况,是每个待排序元素生成一个元组(x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x),排序时是根据这个元组排序,依据是FALSE<TRUE,false排前,true排后,相同则看下一个。sorted最终返回的是需要排序的元素。

    测试代码如下:(来源自dokelungdonghuikey為元組的排序情況,是每個待排序元素產生一個元組(x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper() , x.islower(), x),排序時是根據這個元組排序,依據是FALSE

    測試代碼如下:(來源自dokelungdonghui

    if __name__ == '__main__':
        s = 'asdf234GDSdsf23'
    
        print('key=x')
        s = sorted(s, key=lambda x: x)
        for x in s:
            print((x, x))
    
        print('key=islower()')
        s = sorted(s, key=lambda x: x.islower())
        for x in s:
            print((x.islower(), x))
    
        print('key=isupper()')
        s = sorted(s, key=lambda x: x.isupper())
        for x in s:
            print((x.isupper(), x))
    
        print('key=isdigit() and int(x)%2==0')
        s = sorted(s, key=lambda x: x.isdigit() and int(x) % 2 == 0)
        for x in s:
            print((x.isdigit() and int(x) % 2 == 0, x))
    
        print('key=(x.isupper(), x.islower())')
        s = sorted(s, key=lambda x: (x.isupper(), x.islower()))
        for x in s:
            print((x.isupper(), x.islower(), x))
    
        print('key=(x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))')
        s = sorted(s, key=lambda x: (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))
        for x in s:
            print((x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))

    運行查看輸入可以發現規律。 🎜輸出:🎜
    key=x
    ('2', '2')
    ('2', '2')
    ('3', '3')
    ('3', '3')
    ('4', '4')
    ('D', 'D')
    ('G', 'G')
    ('S', 'S')
    ('a', 'a')
    ('d', 'd')
    ('d', 'd')
    ('f', 'f')
    ('f', 'f')
    ('s', 's')
    ('s', 's')
    key=islower()
    (False, '2')
    (False, '2')
    (False, '3')
    (False, '3')
    (False, '4')
    (False, 'D')
    (False, 'G')
    (False, 'S')
    (True, 'a')
    (True, 'd')
    (True, 'd')
    (True, 'f')
    (True, 'f')
    (True, 's')
    (True, 's')
    key=isupper()
    (False, '2')
    (False, '2')
    (False, '3')
    (False, '3')
    (False, '4')
    (False, 'a')
    (False, 'd')
    (False, 'd')
    (False, 'f')
    (False, 'f')
    (False, 's')
    (False, 's')
    (True, 'D')
    (True, 'G')
    (True, 'S')
    key=isdigit() and int(x)%2==0
    (False, '3')
    (False, '3')
    (False, 'a')
    (False, 'd')
    (False, 'd')
    (False, 'f')
    (False, 'f')
    (False, 's')
    (False, 's')
    (False, 'D')
    (False, 'G')
    (False, 'S')
    (True, '2')
    (True, '2')
    (True, '4')
    key=(x.isupper(), x.islower())
    (False, False, '3')
    (False, False, '3')
    (False, False, '2')
    (False, False, '2')
    (False, False, '4')
    (False, True, 'a')
    (False, True, 'd')
    (False, True, 'd')
    (False, True, 'f')
    (False, True, 'f')
    (False, True, 's')
    (False, True, 's')
    (True, False, 'D')
    (True, False, 'G')
    (True, False, 'S')
    key=(x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))
    (False, False, False, True, 'a')
    (False, False, False, True, 'd')
    (False, False, False, True, 'd')
    (False, False, False, True, 'f')
    (False, False, False, True, 'f')
    (False, False, False, True, 's')
    (False, False, False, True, 's')
    (False, False, True, False, 'D')
    (False, False, True, False, 'G')
    (False, False, True, False, 'S')
    (True, False, False, False, '3')
    (True, False, False, False, '3')
    (True, True, False, False, '2')
    (True, True, False, False, '2')
    (True, True, False, False, '4')

    回覆
    0
  • 取消回覆