如何使用关键参数(非cmp)对混合顺序中的2个元素字符串元组进行排序

时间:2012-02-03 18:45:32

标签: python sorting python-3.x

在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 个答案:

答案 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')

希望这有帮助