在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)]。
答案 0 :(得分:12)
从Python 2.2开始,Python中的排序是stable。
因此,您可以先使用反向标记按第二个值排序:
>>> 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')]
答案 1 :(得分:2)
只需一步:
>>> l.sort(key=lambda t: (t[0], -ord(t[1])))
>>> l
[('a', 'z'), ('a', 'y'), ('a', 'x'), ('b', 'z'), ('b', 'y'), ('b', 'x')]
任何时候你需要对多个键进行排序,你可以使你的键功能成为一个元组,因为元组按字典顺序进行比较。如果您需要对其中一个键进行反向排序,则只需将该元素设为负数。显然你不能只是使字符串为负,所以你首先需要将它转换为ord
的整数。
答案 2 :(得分:2)
Python Sorting HOWTO建议您利用sort stability并分两次进行排序:
>>> 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 :(得分:1)
您可以通过在列表上运行两次排序来完成此操作,首先使用每个元组中第二项的反向排序,然后在新排序的列表中使用正常排序,每个元组中包含第一项。
l = [('a', 'y'),
('a', 'x'),
('b', 'y'),
('b', 'x'),
('b', 'z'),
('a', 'z'),
]
l = sorted(l, key=lambda tup: tup[1], reverse=True)
l = sorted(l, key=lambda tup: tup[0])
或者,如果您愿意:
l = sorted(sorted(l, key=lambda tup: tup[1], reverse=True),
key=lambda tup: tup[0])
答案 4 :(得分:0)
l = [('a', 'x'),
('a', 'y'),
('a', 'z'),
('b', 'x'),
('b', 'y'),
('b', 'z'),
]
>>> sorted(l, key = lambda x: 2*abs(ord(x[0])-ord('a')) + abs(ord(x[1])-ord('z')
希望这有帮助