Custom sorting on a namedtuple class
我经常使用名称双重类。我今天一直在想,如果有一种很好的方法来实现此类的自定义排序,也就是说,将默认排序键设置为不是nameduple的第一个元素(然后是第二个、第三个等)。
我的第一反应是实施
1 2 3 4 5 6 7 8 | from collections import namedtuple from functools import total_ordering @total_ordering class B(namedtuple('B', 'x y')): def __lt__(self, other): return self.y < other.y |
然而:
1 2 3 4 5 | def test_sortingB(): b1 = B(1, 2) b2 = B(2, 1) assert b2 < b1 # passes assert b2 <= b1 # fails |
哦,对了…
所以我想我的选择是
关于解决这一问题的最佳方法的建议?
选项1。使用一个混音器,并将总订购量应用于
1 2 3 4 5 6 7 8 | @total_ordering class B_ordering(object): __slots__ = () # see Raymond's comment def __lt__(self, other): return self.y < other.y class B(B_ordering, namedtuple('B', 'x y')): pass |
选项2。根据
如果,正如您的问题所暗示的那样,您的兴趣仅仅是通过一个备用键对名称进行排序,那么为什么不将sort/sorted
1 2 3 4 5 6 7 | >>> from collections import namedtuple >>> from operator import attrgetter >>> P = namedtuple("P","x y") >>> p1 = P(1, 2) >>> p2 = P(2, 1) >>> sorted([p1, p2], key=attrgetter("y")) [P(x=2, y=1), P(x=1, y=2)] |
您可以进一步定义自己的排序函数:
1 2 3 4 | >>> from functools import partial >>> sortony = partial(sorted, key=attrgetter("y")) >>> sortony([p1, p2]) [P(x=2, y=1), P(x=1, y=2)] |
我的建议是按照您希望的排序顺序创建您的名称与字段的副本。您可能需要更改代码中创建值的部分(例如,将