想写这篇文章是由largest-number这道题引起的。
question:
给你一个列表,类似于[3, 30, 34, 5, 9, 36].你把这些数拼成一个最大的数的字符串,即"953634330“即可
建议自己思考之后再继续朝后看。
---------------------------------------分割线--------------------------------------------
可能猛的一看,这个题好像很好做。只需要按字符串进行排序即可。但是!!!如果你通过字符串的方式进行了排序,可能排序完的结果就变成这样了。[“9”, “5”, “34”, “30”, “3”] 很明显,我们想要的是3排在30的前面。这样不对。那应该根据每个字符的长度吗?也不对,因为34要排在3的前面。怎么做?
不管怎么弄,都得排序。不打算自己排。我就准备用sorted.其实用sort也行。但我还是选用sorted. why?
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.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)
key_wrapper(SortNumber(3)) ->
key_wrapper(SortNumber(30)) ->
key_wrapper(SortNumber(34)) ->
key_wrapper(SortNumber(5)) ->
key_wrapper(SortNumber(9)) ->
key_wrapper(SortNumber(36)) ->
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 就是一个很简单的函数。
a = lambda x,y:x+y
print(a(2,3)) # 这里的x,y是传入的参数,x+y是最终返回值。也可以没有输入只有输出。