通过重新排序元组对元组列表进行排序

5 投票
2 回答
1088 浏览
提问于 2025-04-18 07:54

给定一个要排序的元组列表,Python会先根据元组的第一个元素进行排序,然后是第二个元素,依此类推。

>>> A
[(3, 2, 1), (0, 3, 0), (2, 1, 0), (2, 2, 3), (0, 3, 2), (2, 1, 1), (3, 3, 2), (3, 2, 0)]
>>> sorted(A)
[(0, 3, 0), (0, 3, 2), (2, 1, 0), (2, 1, 1), (2, 2, 3), (3, 2, 0), (3, 2, 1), (3, 3, 2)]

这个方法很好用。现在我想按照第三个元素排序,然后是第一个元素,最后是第二个元素。这个我可以通过提供一个键函数或者比较函数来实现。

>>> A
[(3, 2, 1), (0, 3, 0), (2, 1, 0), (2, 2, 3), (0, 3, 2), (2, 1, 1), (3, 3, 2), (3, 2, 0)]
>>> sorted(A, key = lambda x: (x[2], x[0], x[1]))
[(0, 3, 0), (2, 1, 0), (3, 2, 0), (2, 1, 1), (3, 2, 1), (0, 3, 2), (3, 3, 2), (2, 2, 3)]

不过这样做会导致性能大幅下降。

s ="""\
from numpy.random import randint as rr
A=[tuple(rr(0,10,3)) for i in range(100)]
def tuplecmp(t1, t2):
    return t1[0] - t2[0]
"""
c1 = """\
sorted(A)
"""
c2 = """\
sorted(A, key=lambda x: (x[2], x[0], x[1]))
"""
c3 = """\
sorted(A, cmp = tuplecmp)
"""
import timeit
print timeit.timeit(c1,number=10000, setup= s)
print timeit.timeit(c2,number=10000, setup= s)
print timeit.timeit(c3,number=10000, setup= s)

这会导致

0.60133600235,
0.980231046677,
2.68837809563

此外,我比较元组中各个元素的顺序也不一定要保持不变。我可能需要按照“第二个、第一个,然后是第三个”这样的顺序进行比较。有没有更好的方法可以提供任意的比较函数,而不会造成严重的性能损失呢?

2 个回答

0

我不知道有没有更好的方法来实现你想做的事情。我觉得你总是需要提供自己的比较器,然后就得不断地调用它,这样会有一些开销。

5

使用 operator.itemgetter 作为你的 key 函数可能会更快;你可以试试看。

import operator
sorted(A, key=operator.itemgetter(2, 0, 1))

撰写回答