python的排序问题

python的排序方法有两个

1 nums.sort() # 原数组上排序, 没有返回值, nums变为有序
2 # 或者
3 nums = sorted(nums) # 原数组不变, 会返回一个排好序的新数组

 

那么如何自定义排序规则呢?

自定义排序规则:

假设现在有这么个问题,有n个学生, 每个学生有一个数学成绩,有一个语文成绩, 

要求按照总分从高到低排序,分数一样,再按照数学成绩从低到高, 再一样则按照语文成绩从高到低。

这个问题该怎么解决呢?

对于java, 我们有两种方式,一种是自定义Comparator比较器, 另一种是类实现Comparable接口。

首先我们定义一个学生类:

1 class Student:
2     def __init__(self, math, chinese):
3         self.math = math # 数学成绩
4         self.chinese = chinese # 语文成绩
5 
6     # 总分
7     def sum(self):
8         return self.math + self.chinese

 

python实现自定义排序,比较灵活和简单, 因为sort方法可以接受一个key作为参数, 这个key接受一个函数,

这个函数接受一个参数, 返回一个值, 那么最终就是用这个函数返回的值来比较大小, 从而实现排序。

所以想要自定义排序,我们可以传入一个恰当的函数作为key的值。

比如对于上面提出的问题,排序可以这么写:

1 def cmp(e):
2     return (-e.sum(), e.math, -e.chinese)
3 
4 students.sort(key=cmp)

首先我们定义一个函数cmp, 这个函数接收一个参数, 返回一个值,并将其赋值给key。

那么对students数组排序,实际上相当于对每个数组元素,被cmp函数作用一遍之后的值进行排序。

也就是相当于是对这些返回的元祖进行排序。 然后观察元祖的返回值, 第一个是-e.sum(), 元祖默认是从小到大按数值大小进行排序的,所有就实现了

对学生数组按总分进行从高到低排序了;总分相同,就按照数学成绩从低到高排序了

完整代码如下:

 1 class Student:
 2     def __init__(self, math, chinese):
 3         self.math = math # 数学成绩
 4         self.chinese = chinese # 语文成绩
 5 
 6     # 总分
 7     def sum(self):
 8         return self.math + self.chinese
 9 
10     def __str__(self):
11         return "总分:{},数学:{},语文:{}".format(self.sum(), self.math, self.chinese)
12 
13 n = int(input())
14 students = [None for i in range(n)] # 多个Student对象
15 for i in range(n):
16     a, b = map(int, input().split())
17     students[i] = Student(a, b)
18 
19 def cmp(e):
20     return (-e.sum(), e.math, -e.chinese)
21 
22 students.sort(key=cmp)
23 print(*students, sep='\n')

测试结果如下:

5
60 70
70 60
80 60
75 90
90 75
总分:165,数学:75,语文:90
总分:165,数学:90,语文:75
总分:140,数学:80,语文:60
总分:130,数学:60,语文:70
总分:130,数学:70,语文:60

对于key函数, 我们都是接受一个参数,返回一个值,所以这个函数往往比较简单,所以可以考虑用lambda表达式

可以改成如下代码:

students.sort(key=lambda e: (-e.sum(), e.math, -e.chinese))

基本上用这种方法可以解决绝大部分排序问题

 

重载运算符

在java中我们可以实现一个Comparable接口来让对象具备可比较性。在python当中我们可以通过重载运算符的方式来实现对象之间的可比较性。

python中可以重载的运算符:

dir(object)
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__
', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__',
 '__str__', '__subclasshook__']

通过dir(object)我们可以看到python类当中有很多双下划线开头的方法,这些都是内置方法,有特殊用途。

其中:

__gt__ 对应  大于号 >

__lt__ 对应 小于号 <

__ge__ 对应 大于等于号 >=

__le__ 对应小于等于号 <=

只要重载了其中一个运算符,那么这个类的对象就具备了可比较性

以上文的学生类为例:

完整代码如下:

 1 class Student:
 2     def __init__(self, math, chinese):
 3         self.math = math # 数学成绩
 4         self.chinese = chinese # 语文成绩
 5 
 6     # 总分
 7     def sum(self):
 8         return self.math + self.chinese
 9 
10     def __lt__(self, other):
11         if self.sum() == other.sum():
12             if self.math == other.math:
13                 return self.chinese > other.chinese
14             else:
15                 return self.math < other.math
16         else:
17             return self.sum() > other.sum()
18 
19     def __str__(self):
20         return "总分:{},数学:{},语文:{}".format(self.sum(), self.math, self.chinese)
21 
22 n = int(input())
23 students = [None for i in range(n)] # 多个Student对象
24 for i in range(n):
25     a, b = map(int, input().split())
26     students[i] = Student(a, b)
27 
28 students.sort()
29 print(*students, sep='\n')

测试结果如下:

5
60 70
70 60
80 60
75 90
90 75
总分:165,数学:75,语文:90
总分:165,数学:90,语文:75
总分:140,数学:80,语文:60
总分:130,数学:60,语文:70
总分:130,数学:70,语文:60

重载了小于号运算符 < 后, 任意两个学生对象可以直接进行比较 如 : s1 < s2, 其中s1和s2是学生对象。

那么自然就知道如何比较大小了, 这时候sort函数可以不用传入key,也可以按我们的自定义规则排序了

 

posted @ 2023-02-26 20:43  QWZeng  阅读(161)  评论(0)    收藏  举报