排序方法
2.x的代码移植到3.x时,需要将cmp函数转化为key函数
# Python2 list.sort(cmp=None, key=None, reverse=False) # Python3 list.sort(key=None, reverse=False)
排序有两个方法
list.sort() # list本身将被修改, 返回None sorted() # 不修改原来的list, 返回一个新的list
排序示例
1、list.sort示例
lst = [3, 2, 1] print(lst) # [3, 2, 1] ret = lst.sort() print(ret) # None print(lst) # [1, 2, 3]
2、sorted示例
lst = [3, 2, 1] print(lst) # [3, 2, 1] ret = sorted(lst) print(ret) # [1, 2, 3] print(lst) # [3, 2, 1]
看一个实际需求
有一个人员列表,需要按给定需求排序
from pprint import pprint # name:姓名 # money:钱 # age:年龄 lst = [ { 'name': 'Tom', 'age': 20, 'money': 2000 }, { 'name': 'Jack', 'age': 25, 'money': 2000 }, { 'name': 'Alice', 'age': 25, 'money': 3000 }, { 'name': 'Steve', 'age': 25, 'money': 3000 } ] # 未排序前 pprint(lst) """ [{'age': 20, 'money': 2000, 'name': 'Tom'}, {'age': 25, 'money': 2000, 'name': 'Jack'}, {'age': 25, 'money': 3000, 'name': 'Alice'}, {'age': 25, 'money': 3000, 'name': 'Steve'}] """
1、需求一:单字段排序,钱多的在前
(1)使用lambda 表达式
# 默认从小到大,reverse=True可以逆序排列 lst.sort(key=lambda item: item['money'], reverse=True) pprint(lst) """ [{'age': 25, 'money': 3000, 'name': 'Alice'}, {'age': 25, 'money': 3000, 'name': 'Steve'}, {'age': 20, 'money': 2000, 'name': 'Tom'}, {'age': 25, 'money': 2000, 'name': 'Jack'}] """
(2)使用operator.itemgetter 替换 lambda 表达式
from operator import itemgetter lst.sort(key=itemgetter('money'), reverse=True) pprint(lst) """ [{'age': 25, 'money': 3000, 'name': 'Alice'}, {'age': 25, 'money': 3000, 'name': 'Steve'}, {'age': 20, 'money': 2000, 'name': 'Tom'}, {'age': 25, 'money': 2000, 'name': 'Jack'}] """
(3)使用sorted
from operator import itemgetter lst2 = sorted(lst, key=itemgetter('money'), reverse=True) pprint(lst2) """ [{'age': 25, 'money': 3000, 'name': 'Alice'}, {'age': 25, 'money': 3000, 'name': 'Steve'}, {'age': 20, 'money': 2000, 'name': 'Tom'}, {'age': 25, 'money': 2000, 'name': 'Jack'}] """
以上三种方式排序结果都一样
2、需求二:多字段排序
需要满足3个排序要求
钱money 多的在前面
如果钱money 一样多,年龄age 大的在前
如果钱money 和年龄age 都一样,按照名字首字母顺序排序Z-A排序
如果有一个排序函数就很容易解决
(1) 方式一: 自定义一个排序函数
from functools import cmp_to_key # 自定义一个排序函数 def foo(a, b): if a['money'] > b['money']: return 1 elif a['money'] < b['money']: return -1 else: if a['age'] > b['age']: return 1 elif a['age'] < b['age']: return -1 else: return ord(a['name'][0]) - ord(b['name'][0]) # Python3中需要用到cmp_to_key 函数 lst.sort(key=cmp_to_key(foo), reverse=True) pprint(lst) """ [{'age': 25, 'money': 3000, 'name': 'Steve'}, {'age': 25, 'money': 3000, 'name': 'Alice'}, {'age': 25, 'money': 2000, 'name': 'Jack'}, {'age': 20, 'money': 2000, 'name': 'Tom'}] """
(2)方式二:自定义一个class类,在类中重写排序方法
from functools import total_ordering # 通过__eq__ 和其他(__ne__, __lt__, __gt__)任意一个方法就可以推导出来其他方法 @total_ordering class Person(object): def __init__(self, name, age, money): self.name = name self.age = age self.money = money def __eq__(self, other): return self.money == other.money and \ self.age == other.age and \ ord(self.name[0]) - ord(other.name[0]) def __lt__(self, other): return self.money < other.money or \ self.age < other.age or \ ord(self.name[0]) - ord(other.name[0]) def __str__(self): return f"{{age: {self.age}, money: {self.money}, name: {self.name}}}" __repr__ = __str__ persons = [Person(**item) for item in lst] new_persons = sorted(persons, reverse=True) pprint(new_persons) """ [{age: 25, money: 3000, name: Steve}, {age: 25, money: 3000, name: Alice}, {age: 25, money: 2000, name: Jack}, {age: 20, money: 2000, name: Tom}] """
(3)方式三:使用多个key进行排序
from operator import itemgetter lst.sort(key=itemgetter('money', 'age', 'name'), reverse=True) pprint(lst) """ [{'age': 25, 'money': 3000, 'name': 'Steve'}, {'age': 25, 'money': 3000, 'name': 'Alice'}, {'age': 25, 'money': 2000, 'name': 'Jack'}, {'age': 20, 'money': 2000, 'name': 'Tom'}] """
以上3种方式实现了多个字段排序
参考
python 列表排序方法sort、sorted技巧篇