How to sort a list of objects based on an attribute of the objects?
我有一个python对象列表,我想按对象本身的属性排序。列表如下:
1 2 3 | >>> ut [<Tag: 128>, <Tag: 2008>, <Tag: <>, <Tag: actionscript>, <Tag: addresses>, <Tag: aes>, <Tag: ajax> ...] |
每个对象都有一个计数:
1 2 | >>> ut[1].count 1L |
我需要按计数降序对列表进行排序。
我已经看到了几种方法,但我正在寻找Python中的最佳实践。
1 2 3 4 5 | # To sort the list in place... ut.sort(key=lambda x: x.count, reverse=True) # To return a new list, use the sorted() built-in function... newlist = sorted(ut, key=lambda x: x.count, reverse=True) |
有关按键排序的更多信息»;
最快的方法是使用
1 2 3 4 5 | try: import operator except ImportError: keyfun= lambda x: x.count # use a lambda if no operator module else: keyfun= operator.attrgetter("count") # use operator since it's faster than lambda ut.sort(key=keyfun, reverse=True) # sort in-place |
读者应该注意到key=方法:
1 | ut.sort(key=lambda x: x.count, reverse=True) |
比向对象添加丰富的比较运算符快很多倍。我很惊讶地读到了这篇文章(第485页的"简而言之,Python")。您可以通过在这个小程序上运行测试来确认这一点:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | #!/usr/bin/env python import random class C: def __init__(self,count): self.count = count def __cmp__(self,other): return cmp(self.count,other.count) longList = [C(random.random()) for i in xrange(1000000)] #about 6.1 secs longList2 = longList[:] longList.sort() #about 52 - 6.1 = 46 secs longList2.sort(key = lambda c: c.count) #about 9 - 6.1 = 3 secs |
我的,非常小的,测试显示第一种速度慢了10倍以上,但书中说一般来说只有5倍左右。他们说这是因为python(timsort)中使用了高度优化的排序算法。
不过,非常奇怪的是.sort(lambda)比普通的old.sort()更快。我希望他们能解决这个问题。
1 2 | from operator import attrgetter ut.sort(key = attrgetter('count'), reverse = True) |
面向对象方法
如果适用,最好将对象排序逻辑设置为类的属性,而不是将其合并到需要排序的每个实例中。
这确保了一致性,并消除了对样板代码的需求。
至少,您应该指定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class Card(object): def __init__(self, rank, suit): self.rank = rank self.suit = suit def __eq__(self, other): return self.rank == other.rank and self.suit == other.suit def __lt__(self, other): return self.rank < other.rank hand = [Card(10, 'H'), Card(2, 'h'), Card(12, 'h'), Card(13, 'h'), Card(14, 'h')] hand_order = [c.rank for c in hand] # [10, 2, 12, 13, 14] hand_sorted = sorted(hand) hand_sorted_order = [c.rank for c in hand_sorted] # [2, 10, 12, 13, 14] |
它看起来很像django-orm模型实例的列表。
为什么不在查询时这样排序:
1 | ut = Tag.objects.order_by('-count') |
向对象类添加丰富的比较运算符,然后使用列表的sort()方法。请参阅python中的丰富比较。
更新:虽然这个方法可行,但我认为TripTych的解决方案更适合您的情况,因为它更简单。