Python 中 sorted 如何自定义比较逻辑
在Python中对一个可迭代对象进行排序是很常见的一个操作,一般会用到sorted()函数
num_list=[4,2,8,-9,1,-3] sorted_num_list=sorted(num_list) print(sorted_num_list)
上面的代码是对整数列表num_list按从小到大的顺序进行排序,得到的结果如下
[-9,-3,1,2,4,8]
有时候不仅仅是对元素本身进行排序,而是在元素值的基础上进行一些计算之后再进行比较,比如将num_list中的元素按照其平方值的大小进行排序。
在Python2中,可以通过sorted()函数中的cmp或key参数来实现这种自定义的比较逻辑。cmp比较函数接收两个参数x和y(x和y都是列表中元素)并且返回一个数字,如果返回正数表示x>y,返回0表示x==y,返回负数表示x 但是随着Python3.0的发布,cmp参数也随之被移除了,也就是说在Python3中自定义比较逻辑就只能通过key参数来实现。至于为什么将cmp参数移除,在Python的Issuetracker中有一段很长的讨论,主要有以下两点原因 关于上面性能的问题,我做了一个实验,分别随机生成1000、10000、100000和1000000个整数,然后用key和cmp的方式分别进行排序并记录排序的时间消耗 在我的笔记本上一次运行结果如下 可以看到,当列表中数字的数量超过100000的时候,使用key函数的性能优势就非常明显了,比cmp快了2~3倍。 对于熟悉Java或C++等其他编程语言的同学来说,可能更熟悉cmp的比较方式。其实Python3中也可以通过functools工具包中的cmp_to_key()函数来将cmp转换成key,从而使用接收两个参数的自定义比较函数cmp。 那么,cmp_to_key()函数是如何将cmp转换成key的呢,我们可以通过源码一探究竟 其实cmp_to_key()返回的是一个类K,只不过在类K中重载了各种比较运算符,重载的过程中使用到了自定义的比较函数mycmp,使得K的大小比较逻辑与mycmp一致。这样,对于num_list中的每个元素num都会执行一次K(num)生成一个类K的实例,然后通过比较不同K的实例的大小进行排序。 虽然通过cmp_to_key()可以调用自定义的cmp函数,但是还是要优先使用key函数,因为通过cmp_to_key()方式会在排序过程中创建很多类K的实例,对性能有很大影响,下面是cmp_to_key()和key的性能比较 当num_list中的数量为1000000的时候key比cmp_to_key快了将近15倍。 本文主要介绍了如何在sorted函数中自定义比较逻辑,Python2中可以通过cmp或key来实现,cmp接收2个参数,通过返回的数值来判断两个参数的大小,key重新计算一个新的结果参与比较。在Python3中,考虑到cmp的性能和冗余的原因,将其移除了。在Python3.2中提供了functools.cmp_to_key这个函数来使用自定义的比较函数cmp,但是出于性能的考虑,我们还是要优先使用key来进行排序。 以上就是Python中sorted如何自定义比较逻辑的详细内容,更多关于pythonsorted自定义比较逻辑的资料请关注毛票票其它相关文章!
num_list=[4,2,8,-9,1,-3]
#cmp参数只在Python2中存在,Python3及之后的版本移除了cmp参数
sorted_num_list=sorted(num_list,cmp=lambdax,y:x**2-y**2)
sorted_num_list=sorted(num_list,key=lambdax:x**2)
importrandom
importtime
counts=(1000,10000,100000,1000000)
defcustom_cmp(x,y):
returnx**2-y**2
defcustom_key(x):
returnx**2
print('%7s%20s%20s'%('count','cmp_duration','key_duration'))
forcountincounts:
min_num=-count//2
max_num=count//2
nums=[random.randint(min_num,max_num)for_inrange(count)]
start=time.time()
sorted(nums,cmp=custom_cmp)
cmp_duration=time.time()-start
start=time.time()
sorted(nums,key=custom_key)
key_duration=time.time()-start
print('%7d%20.2f%20.2f'%(count,cmp_duration,key_duration))
countcmp_durationkey_duration
10000.000.00
100000.020.01
1000000.340.11
10000004.751.85
importfunctools
num_list=[4,2,8,-9,1,-3]
defcustom_cmp(x,y):
returnx**2-y**2
sorted_num_list=sorted(num_list,key=functools.cmp_to_key(custom_cmp))
print(sorted_num_list)
defcmp_to_key(mycmp):
"""Convertacmp=functionintoakey=function"""
classK(object):
__slots__=['obj']
def__init__(self,obj):
self.obj=obj
def__lt__(self,other):
returnmycmp(self.obj,other.obj)<0
def__gt__(self,other):
returnmycmp(self.obj,other.obj)>0
def__eq__(self,other):
returnmycmp(self.obj,other.obj)==0
def__le__(self,other):
returnmycmp(self.obj,other.obj)<=0
def__ge__(self,other):
returnmycmp(self.obj,other.obj)>=0
__hash__=None
returnK
countcmp_to_keykey_duration
10000.010.00
100000.100.01
1000001.360.09
100000016.891.13