1. 程式人生 > >python 的sort, sorted,lambda

python 的sort, sorted,lambda

想寫這篇文章是由largest-number這道題引起的。

question:

給你一個列表,類似於[3, 30, 34, 5, 9, 36].你把這些數拼成一個最大的數的字串,即"953634330“即可

建議自己思考之後再繼續朝後看。

---------------------------------------分割線--------------------------------------------

可能猛的一看,這個題好像很好做。只需要按字串進行排序即可。但是!!!如果你通過字串的方式進行了排序,可能排序完的結果就變成這樣了。[“9”, “5”, “34”, “30”, “3”] 很明顯,我們想要的是3排在30的前面。這樣不對。那應該根據每個字元的長度嗎?也不對,因為34要排在3的前面。怎麼做?

不管怎麼弄,都得排序。不打算自己排。我就準備用sorted.其實用sort也行。但我還是選用sorted. why?

這裡得說明一下sorted 和sort的區別。

list.sort()只針對於list才能排序。不信你可以對dict試一下,dict就不行了。sorted則比較全能,字典列表元組都能排序。關鍵是,我的第一反應是用sorted裡面的cmp這個引數來排序。

這裡又有知識點了。

python2裡面的sorted才有cmp這個引數,到了python3,這個引數就被砍掉了!!!

google查了一下,主要是為了防止這個cmp和自帶的cmp產生衝突。所有砍掉了它.那怎麼解決這個問題? 就得用from functools import cmp_to_key

裡面的cmp_to_key了,因為python2.7為了相容python3,增加了它。在python3裡面,就只能用它也解決sorted裡面cmp的問題了。

cmp有了,寫一個函式實現一下這個函式,傳遞給key就完成任務了。怎麼弄?
要判斷 34, 3, 30這個幾個數的順序。我們要做的就是兩個兩個比較。如果343>334,那順序就是34, 3. 如果330>303,那麼順序就是3, 30. 所以這個函式用lambda就能完成。

key=cmp_to_key(lambda x, y: int(y+x), int(x+y))

然後把這個引數傳遞給sorted裡面的key,就完成了排序。但是如果只是這樣的話。這道題可能還是過不去,因為[0, 0]這種情況,你會返回"00",而你應該返回的是"0".
所以還要做一個lstrip(“0”) 如果是空串,就得返回"0"才行。

這個題解到這裡就差不多了。但是我的表演才剛剛開始~~

先來看看被替換為cmp_to_key的cmp是什麼意思。
cmp 就是比較傳入的兩個值x,y 如果x< y, 返回-1. 如果x>y, 返回1. 如果x=y, 返回0.一個lambda就能把兩個值給準備好,傳遞進來就能比較了。但是到底是怎麼比較的?這需要列印更多的訊息,同時,我們不能用lambda. 這裡我舉一個例子。

import functools


class SortNumber:

    def __init__(self, val):
        self.val = val

    def __str__(self):
        return 'SortNumber({})'.format(self.val)


def compare_obj(a, b):
    if int(str(a.val) + str(b.val)) < int(str(b.val) + str(a.val)):
        print('comparing {} and {}, a<b'.format(a, b))
        return 1
    elif int(str(a.val) + str(b.val)) > int(str(b.val) + str(a.val)):
        print('comparing {} and {}, a>b'.format(a, b))
        return -1
    else:
        print('comparing {} and {}, a=b'.format(a, b))
        return 0

# get_key = functools.cmp_to_key(lambda x, y: int(str(y.val) + str(x.val)) - int(str(x.val) + str(y.val)))
get_key = functools.cmp_to_key(compare_obj)


def get_key_wrapper(o):
    "Wrapper function for get_key to allow for print statements."
    new_key = get_key(o)
    print('key_wrapper({}) -> {!r}'.format(o, new_key))
    return new_key


Input = [3, 30, 34, 5, 9, 36]   # [9, 5, 36, 34, 3, 30]
sn = [SortNumber(x) for x in Input]

for o in sorted(sn, key=get_key_wrapper):
    print(o)

result:

key_wrapper(SortNumber(3)) -> <functools.KeyWrapper object at 0x7f34d4e70d30>
key_wrapper(SortNumber(30)) -> <functools.KeyWrapper object at 0x7f34d40198b0>
key_wrapper(SortNumber(34)) -> <functools.KeyWrapper object at 0x7f34d4019ad0>
key_wrapper(SortNumber(5)) -> <functools.KeyWrapper object at 0x7f34d4019ab0>
key_wrapper(SortNumber(9)) -> <functools.KeyWrapper object at 0x7f34d4019a90>
key_wrapper(SortNumber(36)) -> <functools.KeyWrapper object at 0x7f34d4019a70>
comparing 303 < 330, 1
comparing 3430 > 3034, -1
comparing 3430 > 3034, -1
comparing 343 > 334, -1
comparing 53 > 35, -1
comparing 534 > 345, -1
comparing 93 > 39, -1
comparing 934 > 349, -1
comparing 95 > 59, -1
comparing 3634 > 3436, -1
comparing 365 < 536, 1
SortNumber(9)
SortNumber(5)
SortNumber(36)
SortNumber(34)
SortNumber(3)
SortNumber(30)

執行一下,我們大概就能看到sorted裡面的key是如何遍歷的了。但是這裡我確實沒看明白到底是怎麼做的。怎麼辦?
這裡就需要了解python裡面的sorted是怎麼做的了。sorted使用的排序,不是快排,不是歸併。而是一個更快的,效能更好的timsort.

Timsort是結合了合併排序(merge sort)和插入排序(insertion sort)而得出的排序演算法,它在現實中有很好的效率。這個暫時還沒具體研究,學習後再來分享。
最後了再分享一下lambda.
lambda 就是一個很簡單的函式。

example:
a = lambda x,y:x+y
print(a(2,3))   # 這裡的x,y是傳入的引數,x+y是最終返回值。也可以沒有輸入只有輸出。

參考:

https://blog.csdn.net/huangmx1995/article/details/53174366?locationNum=3&fps=1

https://github.com/qiwsir/algorithm/commit/68f1af0cfe3df4a96abc528cd324f5f69f4eb9d

https://blog.csdn.net/yangzhongblog/article/details/8184707

https://www.jb51.net/article/57678.htm

https://blog.csdn.net/weixin_40156487/article/details/82460854