我正在使用python2.6。它是否可以在更高版本的python中使用? 还有其他方法可以维护非平凡类对象列表的优先级队列吗? 我需要的是这样的东西
>>> l = [ ['a', 3], ['b', 1] ]
>>> def foo(x, y):
... return x[1]-y[1]
>>> heap = heapify(l, cmp=foo)
有什么建议吗?
答案 0 :(得分:29)
传统的解决方案是在堆上存储(优先级,任务)元组:
pq = [ ]
heappush(pq, (10, task1))
heappush(pq, (5, task2))
heappush(pq, (15, task3))
priority, task = heappop(pq)
只要没有两个任务具有相同的优先级,这就可以正常工作;否则,比较任务本身(在Python 3中可能根本不起作用)。
常规文档提供了有关如何使用heapq实现优先级队列的指导:
http://docs.python.org/library/heapq.html#priority-queue-implementation-notes
答案 1 :(得分:20)
只需为列表中的对象编写适当的__lt__
方法,以便正确排序:
class FirstList(list):
def __lt__(self, other):
return self[0] < other[0]
lst = [ ['a', 3], ['b', 1] ]
lst = [FirstList(item) for item in lst]
Python只需要__lt__
进行排序,但定义所有比较或使用functools.total_ordering
是个好主意。
通过使用具有相同第一个值和不同第二个值的两个项目,您可以看到它正在工作。无论第二个值是什么,这两个对象都会在您heapify
时交换位置,因为lst[0] < lst[1]
始终为False
。如果您需要heapify
保持稳定,则需要进行更复杂的比较。
答案 2 :(得分:2)
嗯,这太糟糕了,你肯定不应该这样做......但它看起来像heapq
模块defines a cmp_lt
function,如果你真的想要一个自定义比较功能,你可以修补它。
答案 3 :(得分:1)
我不知道这是否更好,但它就像Raymond Hettinger的解决方案,但优先级取决于对象。
让它成为您的对象,并且您希望按x属性进行排序。
class Item:
def __init__(self, x):
self.x = x
然后有一个应用配对的功能
def create_pairs(items):
return map(lambda item: (item.x, item), items)
然后将该函数应用于列表作为heapq.merge
的输入list(heapq.merge(create_pairs([Item(1), Item(3)]),
create_pairs([Item(2), Item(5)])))
这给了我以下输出
[(1, <__main__.Item instance at 0x2660cb0>),
(2, <__main__.Item instance at 0x26c2830>),
(3, <__main__.Item instance at 0x26c27e8>),
(5, <__main__.Item instance at 0x26c2878>)]
答案 4 :(得分:1)
使用这些Heap
和HeapBy
类,我试图简化heapq
的用法。您可以使用HeapBy
来传递键排序功能。
请注意,雷蒙德说,如果重复优先级并且值不可排序,那么他的solution将不会起作用。因此,我添加了一个HeapBy
类的NonComparable
示例。
我从agf's solution采纳了__lt__
的想法。
用法:
# Use HeapBy with a lambda for sorting
max_heap = HeapBy(key=lambda x: -x)
max_heap.push(3)
max_heap.push(1)
max_heap.push(2)
assert max_heap.pop() == 3
assert max_heap.pop() == 2
assert max_heap.pop() == 1
# Use Heap as a convenience facade for heapq
min_heap = Heap()
min_heap.push(3)
min_heap.push(1)
min_heap.push(2)
assert min_heap.pop() == 1
assert min_heap.pop() == 2
assert min_heap.pop() == 3
# HeapBy also works with non-comparable objects.
# Note that I push a duplicated value
# to make sure heapq will not try to call __lt__ on it.
class NonComparable:
def __init__(self, val):
self.val = val
# Using non comparable values
max_heap = HeapBy(key=lambda x: -x.val)
max_heap.push(NonComparable(1))
max_heap.push(NonComparable(1))
max_heap.push(NonComparable(3))
max_heap.push(NonComparable(2))
assert max_heap.pop().val == 3
assert max_heap.pop().val == 2
assert max_heap.pop().val == 1
assert max_heap.pop().val == 1
课程:
import heapq
class Heap:
"""
Convenience class for simplifying heapq usage
"""
def __init__(self, array=None, heapify=True):
if array:
self.heap = array
if heapify:
heapq.heapify(self.heap)
else:
self.heap = []
def push(self, x):
heapq.heappush(self.heap, x)
def pop(self):
return heapq.heappop(self.heap)
class HeapBy(Heap):
"""
Heap where you can specify a key function for sorting
"""
# Item only uses the key function to sort elements,
# just in case the values are not comparable
class Item:
def __init__(self, value, key):
self.key = key
self.value = value
def __lt__(self, other):
return self.key(self.value) < other.key(other.value)
def __init__(self, key, array=None, heapify=True):
super().__init__(array, heapify)
self.key = key
def push(self, x):
super().push(self.Item(x, self.key))
def pop(self):
return super().pop().value