我有一个Python对象列表,我想按对象本身的属性对其进行排序。该列表如下所示:
>>> ut
[<Tag: 128>, <Tag: 2008>, <Tag: <>, <Tag: actionscript>, <Tag: addresses>,
<Tag: aes>, <Tag: ajax> ...]
每个对象都有一个计数:
>>> ut[1].count
1L
我需要按递减计数对列表进行排序。
我已经看到了几种方法,但是我正在寻找Python的最佳实践。
我有一个Python对象列表,我想按对象本身的属性对其进行排序。该列表如下所示:
>>> ut
[<Tag: 128>, <Tag: 2008>, <Tag: <>, <Tag: actionscript>, <Tag: addresses>,
<Tag: aes>, <Tag: ajax> ...]
每个对象都有一个计数:
>>> ut[1].count
1L
我需要按递减计数对列表进行排序。
我已经看到了几种方法,但是我正在寻找Python的最佳实践。
Answers:
# 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)
有关按键排序的更多信息。
可以使用最快的方法,尤其是在您的列表中有很多记录的情况下operator.attrgetter("count")
。但是,它可以在预操作者版本的Python上运行,因此具有后备机制会很好。然后,您可能需要执行以下操作:
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
self.__dict__ = {'some':'dict'}
在__init__
方法之后完成操作)。不过,我不知道为什么会有所不同。
__dict__
。注意,“具有动态添加的属性的对象”和“设置对象的__dict__
属性”几乎是正交的概念。我说这是因为您的评论似乎暗示着设置__dict__
属性是动态添加属性的必要条件。
operator.attrgetter
,则可以提供具有任何属性名称的函数并返回已排序的集合。
读者应注意,key =方法:
ut.sort(key=lambda x: x.count, reverse=True)
比向对象添加丰富的比较运算符快许多倍。我很惊讶地阅读了这篇文章(“ Python in a Nutshell”的第485页)。您可以通过在这个小程序上运行测试来确认这一点:
#!/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)比普通的旧.sort()快是很奇怪的。我希望他们能解决这个问题。
__cmp__
等效于调用.sort(cmp=lambda)
,而不是.sort(key=lambda)
,因此一点都不奇怪。
longList2.sort(cmp = cmp)
。我尝试了一下,其效果几乎与相同.sort()
。(另外:请注意,“ cmp”排序参数已在Python 3中删除。)
面向对象的方法
最好将对象排序逻辑(如果适用)设置为类的属性,而不是在每个实例中都要求进行排序。
这样可以确保一致性,并且不需要样板代码。
至少,您应该指定__eq__
和__lt__
操作此功能。然后使用sorted(list_of_objects)
。
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]
__eq__
和__lt__
是最低实施要求?
from operator import attrgetter
ut.sort(key = attrgetter('count'), reverse = True)
它看起来很像Django ORM模型实例的列表。
为什么不对这样的查询进行排序:
ut = Tag.objects.order_by('-count')