search

Home  >  Q&A  >  body text

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接受的函数返回的是一个元组?是如何进行比较的?

高洛峰高洛峰2784 days ago1465

reply all(3)I'll reply

  • 伊谢尔伦

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

    First compare the first value of the tuple, FALSE<TRUE, if equal, compare the next value of the tuple, and so on.

    reply
    0
  • PHP中文网

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

    Let’s start with a simple example:

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

    Result:

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

    items is a list of tuples. If you sort the tuples, Python's Builtin function sorted (or sort) will start from the tuples. Sorting starts from the last element of , that is to say, sorting a set of two-element tuples can be imagined as two basic sortings: 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()

    was originally:
    print('key=isdigit()')
    s = sorted(s ,key=lambda x: x.isdigit())
    show(s)
    

    The first sort uses the second element as the key, so the sorting result is:

    sorted(s, key=lambda x: (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x.isupper(), x.islower(), x))
    
    The second sort uses the first element as the key, so the sorting result is:

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

    Conclusion(1)
    :

    The sorting of tuples is sorted from the last element forward
    That is to say, the sorting weight of tuples starts from the first element and decreases backwards.

    Then let’s observe the sorting of Boolean values:
    rrreee

    Result:

    rrreee

    Conclusion 2

    :

    Boolean sorting will place False in the front and True in the back

    Then let’s take a look at the example you gave. Let’s write a simple function to observe the results:

    rrreee

    function show will print out the current string s which is used to generate the tuple key for each character during sorting. #🎜🎜# #🎜🎜#Then we apply the conclusion 1 just now. Instead of using tuple as key, we use the equivalent #🎜🎜# to sort the key from the last element forward #🎜🎜#, and gradually observe s and tuple key changes: #🎜🎜# rrreee #🎜🎜#We will find that, as expected, according to conclusion (1), this approach is indeed equivalent to sorting with tuple as the key in one go.
    Observe at the same time, conclusion (2), for the Boolean keys generated by isdigit(), isupper(), islower(), etc. Generally speaking, the sorting results are as expected. #🎜🎜# rrreee #🎜🎜# #🎜🎜#But I think this is not our final conclusion, because this is a coincidental result (it may be too much to say it happened, it should be said to be a less intuitive result), let us conclude based on #🎜🎜#(1 )#🎜🎜# Analysis of the initial example: #🎜🎜# rrreee #🎜🎜#We can translate this sorting into: #🎜🎜# #🎜🎜##🎜🎜#First sort the character x itself, and then sort whether the character is lowercase, whether the character is uppercase, whether the character is an even number, and whether the character is a number. #🎜🎜##🎜🎜# #🎜🎜# can also be translated into: #🎜🎜# #🎜🎜##🎜🎜# We use whether the character is a number as the highest sorting weight, and then we use whether the character is an even number, whether the character is uppercase, whether the character is lowercase, and the character x itself as the weight. #🎜🎜##🎜🎜# #🎜🎜#This seems to be different from the initial goal (#Sort: lowercase-uppercase-odd-even), at least it has no intuitive correspondence with the goal. #🎜🎜# #🎜🎜# is suggested to be changed to: #🎜🎜# rrreee #🎜🎜# can be interpreted as: #🎜🎜# #🎜🎜##🎜🎜#We use whether the character is lowercase as the highest weight, and then use whether the character is uppercase, whether the character is an odd number, and the character x itself as the weight to sort #🎜🎜#

    Interesting thing is: we want to make the predicate True 的字元在排序完成後在比較前面的位置,所以根據結論(2)加了一個 not so that the matching characters can be in front.

    reply
    0
  • 高洛峰

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

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

    测试代码如下:(来源自dokelungdonghuikey is the sorting situation of the tuple. Each element to be sorted generates a tuple (x.isdigit(), x.isdigit() and int(x) % 2 == 0, x. isupper(), x.islower(), x), the sorting is based on this tuple, based on FALSE<TRUE, false is ranked first, true is ranked last, if they are the same, look at the next one. sorted ultimately returns the elements that need to be sorted.

    The test code is as follows: (from dokelung and donghui)

    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))

    Run and view the input to find patterns. #🎜🎜#Output: #🎜🎜#
    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')

    reply
    0
  • Cancelreply