如何结合operator.itemgetter与三元逻辑实现字典列表排序?
搞定「优先用two排序,无值则用one」的需求
嘿,你之前的思路方向是对的,但踩了个小坑:你直接判断itemgetter('two')这个对象本身,而不是判断每个字典项里的two值。itemgetter返回的是一个可调用函数,永远会被视为真值,所以你的三元表达式永远只会取itemgetter('two'),根本不会触发one的分支。
下面给你两种适配现有代码结构的解决方案,都能得到你想要的输出:
方案一:用Lambda表达式直接实现条件判断(最直观)
直接在key的lambda里针对每个item做判断:如果two不为None就用它排序,否则用one。完美契合你的需求:
from operator import itemgetter items = [ {'title': 'C Item', 'something': 1.5, 'one': 2, 'two': 3}, {'title': 'B Item', 'something': 1.0, 'one': 1, 'two': None}, {'title': 'D Item', 'something': 1.5, 'one': 4, 'two': None}, {'title': 'A Item', 'something': 2.0, 'one': 3, 'two': 2}, ] mappings = { 'title-desc': {'key': lambda: itemgetter('title'), 'reverse': True}, 'smth-asc': {'key': lambda: itemgetter('something'), 'reverse': False}, # 核心改动:用嵌套lambda捕获每个item,实现条件取值 'one/two-asc': {'key': lambda: lambda item: item['two'] if item['two'] is not None else item['one'], 'reverse': False}, } results = {} for key, value in mappings.items(): sorted_items = sorted(items, key=value['key'](), reverse=value['reverse']) sorted_values = {key: [item['title'] for item in sorted_items]} results.update(sorted_values) print(results)
运行后会输出你期望的结果:
{ 'title-desc': ['D Item', 'C Item', 'B Item', 'A Item'], 'smth-asc': ['B Item', 'C Item', 'D Item', 'A Item'], 'one/two-asc': ['B Item', 'A Item', 'C Item', 'D Item'] }
方案二:结合itemgetter和辅助函数(风格更统一)
如果你偏好保持和其他排序规则一致的itemgetter风格,可以把条件逻辑封装成一个辅助函数,这样代码看起来更规整:
from operator import itemgetter items = [ {'title': 'C Item', 'something': 1.5, 'one': 2, 'two': 3}, {'title': 'B Item', 'something': 1.0, 'one': 1, 'two': None}, {'title': 'D Item', 'something': 1.5, 'one': 4, 'two': None}, {'title': 'A Item', 'something': 2.0, 'one': 3, 'two': 2}, ] # 封装条件逻辑的辅助函数,返回一个排序用的key函数 def get_two_or_one(): getter_two = itemgetter('two') getter_one = itemgetter('one') return lambda item: getter_two(item) if getter_two(item) is not None else getter_one(item) mappings = { 'title-desc': {'key': lambda: itemgetter('title'), 'reverse': True}, 'smth-asc': {'key': lambda: itemgetter('something'), 'reverse': False}, 'one/two-asc': {'key': get_two_or_one, 'reverse': False}, } results = {} for key, value in mappings.items(): sorted_items = sorted(items, key=value['key'](), reverse=value['reverse']) sorted_values = {key: [item['title'] for item in sorted_items]} results.update(sorted_values) print(results)
这个方案把条件判断逻辑抽离出来,和其他排序规则的写法保持一致,可读性也很好。
再说说你原来写法的问题
你最初尝试的itemgetter('two') if itemgetter('two') else itemgetter('one')之所以不生效,是因为:
itemgetter('two')创建的是一个可调用对象,在Python中,只要不是None、空容器这类假值,都会被视为True- 所以这个表达式永远会返回
itemgetter('two'),完全不会触发else分支 - 我们需要的是针对每个item的
two值做判断,而不是判断itemgetter对象本身
内容的提问来源于stack exchange,提问作者4dyc0wzn
相关产品推荐
相关产品推荐

