-
python3之后不支持cmp,所用key函數並不直接比較任意兩個原始元素,而是通過key函數把那些元素轉換成一個個新的可比較對象,也就是元素的key,然后用元素的key代替元素去參與比較。如果原始元素本來就是可比較對象,比如數字、字符串,那么不考慮性能優化可以直接sort(key=lambda e: e)。不過這種基於key函數的設計傾向於每個元素的大小有個絕對標准,但有時卻會出現單個元素並沒有一個絕對的大小的情況,此時可以使用 functools.cmp_to_key構建基於多個元素的比較函數。
-
以一個leetcode上的題為例:
179. 最大數 給定一組非負整數 nums,重新排列每個數的順序(每個數不可拆分)使之組成一個最大的整數。 注意:輸出結果可能非常大,所以你需要返回一個字符串而不是整數。 示例 1: 輸入:nums = [10,2] 輸出:"210" 示例 2: 輸入:nums = [3,30,34,5,9] 輸出:"9534330" 示例 3: 輸入:nums = [1] 輸出:"1" 示例 4: 輸入:nums = [10] 輸出:"10" 提示: 1 <= nums.length <= 100 0 <= nums[i] <= 109可以看到在這道題中列表nums中兩個值的相對位置並不能由單一num決定,而是說 x與y拼接比y與x拼接的值大,那么就用[x,y]的順序,否則用[y,x]的順序。此時就是所謂的:單個元素並沒有一個絕對的大小的情況
-
要解決這道題用sort也很簡單:
from functools import cmp_to_key class Solution: def largestNumber(self, nums: List[int]) -> str: nums.sort(key=cmp_to_key(lambda x,y: int(str(y)+str(x)) - int(str(x)+str(y)))) ans = ''.join([str(num) for num in nums]) return str(int(ans))或者
from functools import cmp_to_key def auxComp(x, y): if int(str(x)+str(y)) > int(str(y)+str(x)): return -1 elif int(str(x)+str(y)) < int(str(y)+str(x)): return 1 else: return 0 class Solution: def largestNumber(self, nums: List[int]) -> str: nums.sort(key=cmp_to_key(auxComp)) ans = ''.join([str(num) for num in nums]) return str(int(ans))至於cmp_to_key中函數的條件可以這樣理解:
sort本身是升序,而題目要求是降序,因此需要cmp_to_key中反着寫(或者加上reverse=True),也就是解法中的:
lambda x,y: int(str(y)+str(x)) - int(str(x)+str(y))以及
def auxComp(x, y): if int(str(x)+str(y)) > int(str(y)+str(x)): return -1 elif int(str(x)+str(y)) < int(str(y)+str(x)): return 1 else: return 0 -
一句話說:python3中一些接受key的函數中(例如sorted,min,max,heapq.nlargest,itertools.groupby),key僅僅支持一個參數,無法實現兩個參數之間的對比。采用cmp_to_key 函數,可以接受兩個參數,對兩個參數做處理,比如做和做差,轉換成一個參數,就可以應用於key關鍵字了。
參考:
