我实现了一个带有数字属性的对象。我想保留根据该属性排序的那些对象的列表,而不需要在每次插入时运行排序方法。我看了一下bisect模块,但我不知道我是否也可以将它与一个对象一起使用。 最好的方法是什么?
答案 0 :(得分:9)
如果您实施__lt__
方法,则可以为自定义对象执行此操作,因为this is what bisect will use可以比较您的对象。
>>> class Foo(object):
... def __init__(self, val):
... self.prop = val # The value to compare
... def __lt__(self, other):
... return self.prop < other.prop
... def __repr__(self):
... return 'Foo({})'.format(self.prop)
...
>>> sorted_foos = sorted([Foo(7), Foo(1), Foo(3), Foo(9)])
>>> sorted_foos
[Foo(1), Foo(3), Foo(7), Foo(9)]
>>> bisect.insort_left(sorted_foos, Foo(2))
>>> sorted_foos
[Foo(1), Foo(2), Foo(3), Foo(7), Foo(9)]
答案 1 :(得分:2)
您可以提供列表的自定义实现,该实现覆盖进行二进制插入的insert方法。软管插入元素的时间从O(1)到O(log2(n)),其中n是列表中元素的数量。
您也可以使用已实现的实现,例如已排序的容器[http://www.grantjenks.com/docs/sortedcontainers/]。
无论如何,无论你使用什么解决方案,你必须在你的对象上实现比较器方法(大于(__gt__
)和小于(__lt__
)),这些方法使用这个数字属性来定义你的命令。对象。没有订单,就没有可能的分类。
这是一个例子:
from sortedcontainers import SortedList
class OrderedObject():
def __init__(self, id, value):
self.id = id
self.value = value
def __gt__(self, other):
if not isinstance(other,OrderedObject):
raise Exception("OrderedObject are only comparable to OrderedObject, not to {0}".format(type(other)))
else:
return self.value.__gt__(other.value)
def __lt__(self, other):
if not isinstance(other,OrderedObject):
raise Exception("OrderedObject are only comparable to OrderedObject, not to {0}".format(type(other)))
else:
return self.value.__lt__(other.value)
def __repr__(self):
return "<OrderedObject({0}, {1})>".format(self.id, self.value)
if __name__ == "__main__":
a = OrderedObject('foo', 1)
b = OrderedObject('bar', 2)
c = OrderedObject('-*-', 3)
mylist = [b,c,a]
print(mylist)
mylist.sort()
print(mylist)
mylist = SortedList()
mylist.add(b)
mylist.add(c)
mylist.add(a)
print(mylist)
这给出了以下结果:
[<OrderedObject(bar, 2)>, <OrderedObject(-*-, 3)>, <OrderedObject(foo, 1)>]
[<OrderedObject(foo, 1)>, <OrderedObject(bar, 2)>, <OrderedObject(-*-, 3)>]
SortedList([<OrderedObject(foo, 1)>, <OrderedObject(bar, 2)>, <OrderedObject(-*-, 3)>])
注意:我没有以任何方式加入已排序的容器库
答案 2 :(得分:1)
bisect不支持密钥;阅读本文:http://bugs.python.org/issue4356并且出于性能原因,他们并不打算支持这一点。但我认为如果您使用__gt__
,__lt__
等
答案 3 :(得分:0)
您可以通过以下方式减少排序:
应在插入新数据时执行特殊变量的修改。