1.functools.cmp_to_key()是什么
简单来说,它的功能就是定义排序时的规则,使数组按照自己定义的规则进行排序。
2.functools.cmp_to_key()怎么用
举例来说:一个数组[1,0,-10,200,3,7],正常按照从小到大进行排序,结果为:[-10, 0, 1, 3, 7, 200]。
3.functools.cmp_to_key(callable)框架
下面代码的1表示相反,-1表示保持。
(1).单个比较
这个框架是单层的if-elif-else,适用于单个比较大小
import functools
def mycmp(x,y): # 只需要把func(x)和func(y)改成你想要的规则
if func(x) > func(c):
return 1
elif func(x) < func(y):
return -1
else:
return 0
if __name__ == '__main__':
arr = [a,b,c,d,e,f,.....] # 字母代表你需要排序的数字
arr.sort(key=functools.cmp_to_key(mycmp))
print(arr)
(2).有优先级的比较
两个或者三个有优先级的比较的话需要两层if-elif-else。
以三个有优先级的比较为例:优先级为(1,2,0),a[1]和a[2]降序,a[0]升序。
import functools
def cmp(n1,n2):
if n1[1]!=n2[1]: # 1不一样,降序
return -1 if n1[1]>n2[1] else 1
elif n1[2] != n2[2]: # 2不一样,降序
return -1 if n1[2]>n2[2] else 1
else: # 0不一样,升序
return 1 if n1[0]>n2[0] else -1
先比较第一个:a[1],再比较第二个a[2],最后比较第0个:a[0]
4.举例
如果我们想按照数组中元素的绝对值进行排序,可以把上面框架中的func(x)和func(y)改成abs(x)和abs(y)即可。那我们就可以采用如下的代码:
import functools
def mycmp(x,y):
if abs(x) > abs(y): # 1表示相反,-1表示保持
return 1
elif abs(x) < abs(y):
return -1
else:
return 0
if __name__ == '__main__':
arr = [1,0,-10,200,3,7]
arr.sort(key=functools.cmp_to_key(mycmp))
print(arr)
# 打印结果:[0, 1, 3, 7, -10, 200]
上述代码中我们定义排序规则mycmp:对于两个数字x和y,我们定义绝对值大的为“大”,绝对值小的为“小”。之后我们通过key参数告诉数组的内置函数sort,让它明白如何对两个数进行比较,清楚哪个是“大”的,哪个是“小”的。比如对于0和-10,|0|<|-10|,因此对于规则mycmp,0<-10。(注:定义排序规则只是为了明白如何得到两个数之间较“大”的一个,与数组是从“小”到“大”还是从“大”到“小”排序,是没有关系的,这个是由排序的另一个参数:reverse = True/False来确定,我们定义排序规则,只是需要弄清楚谁是“大”的)
再举一个栗子,我们想按照数组中元素的相反数进行排序(从小到大),只需要把上面框架中的func(x)和func(y)改成-x和-y即可。
import functools
def mycmp(x,y):
if -x > -y:
return 1 # 相反
elif -x < -y:
return -1 # 保持
else:
return 0
if __name__ == '__main__':
arr = [1,0,-10,200,3,7]
arr.sort(key=functools.cmp_to_key(mycmp))
print(arr)
# 打印结果:[200, 7, 3, 1, 0, -10]
特殊情况:以下面第三行代码进行说明:如果y-x<0,则等价于-1的情况,不需要交换,即前面比后面大,降序;同理,y-x>0等价于1,交换,即前面大于后面,降序。第四行代码也是这样去分析。
from functools import cmp_to_key
nums = [3, 30, 34, 5, 9]
new_nums = sorted(nums, key=cmp_to_key(lambda x, y: y - x)) # 后-前 降序
new_nums2 = sorted(nums, key=cmp_to_key(lambda x, y: x - y)) # 前-后 升序
print(new_nums)
print(new_nums2)
#结果:
#[34, 30, 9, 5, 3]
#[3, 5, 9, 30, 34]
5.蓝桥杯省赛实战
这道题是一个有优先级的三比较的题目 ,先总分,再语文,最后学号,需要两层if-elif-else,第一层是判断总分是同(if)/语文是否相同(elif)/(else),第二层分别比较总分/语文/学号
import functools
def cmp(n1,n2):
if n1[1]!=n2[1]: # 总分不一样的,高分在前
return -1 if n1[1]>n2[1] else 1
elif n1[2] != n2[2]: # 总分一样,语文不一样的,语文高在前
return -1 if n1[2]>n2[2] else 1
else: # 成绩,语文都一样的,学号小的在前
return 1 if n1[0]>n2[0] else -1
n = int(input())
scores = []
for i in range(n):
score = list(map(int,input().split()))
scores.append([i+1,sum(score)]+score)
# scores.sort(key=functools.cmp_to_key(cmp)) # 用sort
scores = sorted(scores,key=functools.cmp_to_key(cmp)) # 用sorted
for i in range(5):
print(scores[i][0],scores[i][1])