我正在使用Python2.6。它是否适用于更高版本的Python?
否则,是否有其他方法可以为非平凡类对象列表维护优先级队列?我需要像这样的东西
>>> l = [ ['a', 3], ['b', 1] ]
>>> def foo(x, y):
... return x[1]-y[1]
>>> heap = heapify(l, cmp=foo)
有什么建议吗?
我正在使用Python2.6。它是否适用于更高版本的Python?
否则,是否有其他方法可以为非平凡类对象列表维护优先级队列?我需要像这样的东西
>>> l = [ ['a', 3], ['b', 1] ]
>>> def foo(x, y):
... return x[1]-y[1]
>>> heap = heapify(l, cmp=foo)
有什么建议吗?
由于内置函数不直接支持cmp函数,因此我们需要构建heapify和heappop的新变体:
from heapq import heapify, heappop
from functools import cmp_to_key
def new_heapify(data, cmp):
s = list(map(cmp_to_key(cmp), data))
heapify(s)
return s
def new_heappop(data):
return heappop(data).obj
那些用法与你的示例相同:
>>> l = [ ['a', 3], ['b', 1] ]
>>> def foo(x, y):
... return x[1]-y[1]
...
>>> heap = new_heapify(l, cmp=foo)
>>> new_heappop(heap)
['b', 1]
一个更传统的解决方案是在堆上存储 (优先级, 任务) 元组:
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
np.array
时,这也会引起麻烦,因为它们在比较时不会产生布尔值。 - Eric为列表中的对象编写适当的__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
稳定,你需要进行更复杂的比较。
Heap
和HeapBy
类,我试图简化heapq
的使用。使用HeapBy
可以传递一个键排序函数。NonComparable
类的HeapBy
示例。__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
好吧,这是可怕的,绝对不应该这样做...但看起来heapq
模块定义了一个cmp_lt
函数,如果你真的想要一个自定义比较函数,你可以使用monkey patch。
heapq
模块会让其他代码遭受可怕的破坏和损害,而试图对heapq
模块进行猴子补丁操作的代码则会变得更加糟糕。最好的方法是遵循Raymond Hettinger的建议,他是Python中实现此类算法模块的作者之一。 - David Woleverimport heapq
然后 heapq.cmp_lt = lambda x, y: x.value < y.value
不起作用呢?(在我的情况下,我将比较具有值的节点)。 - Csaba Tothclass Item:
def __init__(self, x):
self.x = x
def create_pairs(items):
return map(lambda item: (item.x, item), items)
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>)]