如何使用key参数(而非cmp)对混合顺序的字符串二元组排序
在Python中,我有一些像下面这样的东西(虽然顺序是随机的):
l = [('a', 'x'),
('a', 'y'),
('a', 'z'),
('b', 'x'),
('b', 'y'),
('b', 'z'),
]
如果我调用 sorted(l)
,我会得到一个排序后的结果(就像上面那样),这是大家所期待的。不过,我需要的是对元组的第一个元素进行正序排序,而对第二个元素进行倒序排序。换句话说,我想要这样的结果:
l = [('a', 'z'),
('a', 'y'),
('a', 'x'),
('b', 'z'),
('b', 'y'),
('b', 'x'),
]
在Python2.x中,有一个叫 cmp
的参数可以传给 sorted()
来实现这个结果,但在Python3中这个参数就没有了。现在只有一个 key
参数。有没有办法仅用 key
参数来达到我想要的排序顺序呢?
我知道我可以定义一个新的类来包装我的元组,或者使用像 functools.cmp_to_key
这样的东西(这也会创建一个包装类),但对于这么简单的操作来说,这些方法似乎太复杂了。难道就没有其他的办法吗?
补充说明:我应该提到,这些字符串不全是单字符的,并且在某些情况下,元组列表中还包含非字符串数据(例如 (basestring, datetime))。
5 个回答
2
Python的排序指南建议你利用排序的稳定性,并且可以分两次来进行排序:
>>> l.sort(key=lambda t: t[1], reverse=True) # SECONDARY KEY: field 1 descending
>>> l.sort(key=lambda t: t[0]) # PRIMARY KEY: field 0 ascending
>>> l
[('a', 'z'), ('a', 'y'), ('a', 'x'), ('b', 'z'), ('b', 'y'), ('b', 'x')]
3
一步到位:
>>> l.sort(key=lambda t: (t[0], -ord(t[1])))
>>> l
[('a', 'z'), ('a', 'y'), ('a', 'x'), ('b', 'z'), ('b', 'y'), ('b', 'x')]
当你需要根据多个条件进行排序时,可以把你的排序条件做成一个元组,因为元组是按照字典顺序比较的。如果你想要对其中一个条件进行反向排序,只需要把那个条件的值变成负数。显然,你不能直接把字符串变成负数,所以你需要先用 ord
函数把它转换成一个整数。
12
在Python中,从2.2版本开始,排序是稳定的,这意味着如果有两个元素的排序条件相同,它们的相对位置不会改变。
所以,你可以先根据第二个值进行排序,并且可以使用反向标志来改变排序顺序:
>>> from operator import itemgetter
>>> l.sort(key=itemgetter(1), reverse=True)
>>> l
[('a', 'z'), ('b', 'z'), ('a', 'y'), ('b', 'y'), ('a', 'x'), ('b', 'x')]
然后你可以根据第一个值进行排序:
>>> l.sort(key=itemgetter(0))
>>> l
[('a', 'z'), ('a', 'y'), ('a', 'x'), ('b', 'z'), ('b', 'y'), ('b', 'x')]