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是最終返回值。也可以沒有輸入只有輸出。