Python实现User对象列表先按name降序再按id升序排序
Python多字段不同排序方向实现方法
直接给sorted传单key加reverse=True/False只能统一控制所有排序字段的升降序,要实现不同字段对应不同排序方向,有3种常用写法,无需额外依赖:
方案1:利用稳定排序两次排序(通用首选,兼容所有字段类型)
Python内置的sorted是稳定排序:当两个元素的排序键相等时,会保留它们在排序前列表里的相对位置。利用这个特性,我们只要从低优先级到高优先级依次排序就行:
- 需求里第二优先级是id升序,属于低优先级规则,先排
- 第一优先级是name降序,属于高优先级规则,后排,排的时候传
reverse=True实现倒序
修正后的完整可运行代码:
class User: def __init__(self, id, name): self.id = id self.name = name def sorts(users): # 第一步:先按低优先级规则 id升序 排序 users = sorted(users, key=lambda x: x.id) # 第二步:再按高优先级规则 name降序 排序,稳定排序会自动保留name相同元素的id升序顺序 users = sorted(users, key=lambda x: x.name, reverse=True) for u in users: print(u.name, u.id) # 测试数据,额外加了两个name为Andy的实例,用来验证id升序的第二规则 user1 = User(41, 'John') user2 = User(32, 'Doe') user3 = User(93, 'Mary') user4 = User(412, 'Andrew') user5 = User(54, 'Jesus') user6 = User(62, 'Abigale') user7 = User(37, 'Waldo') user8 = User(18, 'Abby') user9 = User(92, 'Andy') user10 = User(10, 'Hulk') user11 = User(117, 'Ron') user12 = User(2, 'Andy') user13 = User(100, 'Andy') users= [user1, user2, user3 , user4 ,user5 ,user6 ,user7 ,user8, user9, user10, user11, user12, user13] sorts(users)
运行后可以看到所有name从Z到A倒序排列,同名的Andy会按id从小到大(2、92、100)排列,完全符合需求。
方案2:单轮key转换(性能最好,仅适用于数值类降序字段)
如果需要降序的字段是数值类型,可以直接在key元组里对降序字段取负值,一次排序完成,性能比两次排序更高。但当前需求里需要降序的是字符串类型的name字段,这个方法不适用,举个适用场景的例子:如果需求是「id降序、name升序」,可以直接写:
# 降序的数值字段前面加负号即可 users = sorted(users, key=lambda x: (-x.id, x.name))
方案3:自定义比较函数(逻辑直观,适合复杂规则)
如果排序规则很复杂,没法简单通过key转换实现,可以用functools.cmp_to_key自定义比较逻辑:比较函数接收两个元素a、b,返回负数表示a排在b前面,返回正数表示b排在a前面,返回0表示两者相等。
from functools import cmp_to_key def user_cmp(a, b): # 先判断name的降序规则 if a.name > b.name: return -1 elif a.name < b.name: return 1 # name相等时走id升序规则 else: return a.id - b.id def sorts(users): users = sorted(users, key=cmp_to_key(user_cmp)) for u in users: print(u.name, u.id)
这个方法的缺点是排序性能比key写法差,数据量特别大的时候不推荐用。
小提示:Python类名推荐用大驼峰命名,原来的
user类名建议改成User,避免和循环变量、实例名重名引发bug。
内容的提问来源于stack exchange,提问作者user17775845
相关产品推荐
相关产品推荐

