我希望拥有一堆物品,而不仅仅是数字。它们将具有一个整数属性,堆可以按其排序。在python中使用堆的最简单方法是heapq,但在使用heapq时如何告诉它按特定属性排序?
答案 0 :(得分:47)
heapq
以与list.sort
相同的方式对对象进行排序,因此只需在类定义中定义一个方法__cmp__()
,它将自己与同一个类的另一个实例进行比较:
def __cmp__(self, other):
return cmp(self.intAttribute, other.intAttribute)
适用于Python 2.x。
在3.x中使用:
def __lt__(self, other):
return self.intAttribute < other.intAttribute
答案 1 :(得分:38)
根据documentation中的示例,您可以使用元组,它将按元组的第一个元素排序:
>>> h = []
>>> heappush(h, (5, 'write code'))
>>> heappush(h, (7, 'release product'))
>>> heappush(h, (1, 'write spec'))
>>> heappush(h, (3, 'create tests'))
>>> heappop(h)
(1, 'write spec')
因此,如果您不想(或不能?)执行__cmp__
方法,您可以在推送时手动提取排序键。
请注意,如果一对元组中的第一个元素相等,则会比较更多元素。如果这不是您想要的,您需要确保每个第一个元素都是唯一的。
答案 2 :(得分:4)
根据Official Document,一种解决方案是将条目存储为元组(请查看 8.4.1 和 8.4.2 节) )。
例如,您的对象就是 tuple 格式的对象 (键,值_1,值_2)
将对象(即 tuples )放入 heap 时,它将比较对象中的第一个属性(在这种情况下为 key >)进行比较。如果发生平局,堆将使用下一个属性(即 value_1 ),依此类推。
例如:
import heapq
heap = []
heapq.heappush(heap, (0,'one', 1))
heapq.heappush(heap, (1,'two', 11))
heapq.heappush(heap, (1, 'two', 2))
heapq.heappush(heap, (1, 'one', 3))
heapq.heappush(heap, (1,'two', 3))
heapq.heappush(heap, (1,'one', 4))
heapq.heappush(heap, (1,'two', 5))
heapq.heappush(heap, (1,'one', 1))
show_tree(heap)
输出:
(0, 'one', 1)
(1, 'one', 1) (1, 'one', 4)
(1, 'one', 3) (1, 'two', 3) (1, 'two', 2) (1, 'two', 5)
(1, 'two', 11)
关于用python漂亮打印堆(更新了链接):show_tree()
答案 3 :(得分:3)
不幸的是,你不能,尽管这是一个经常被要求的功能。
一种选择是将(key,value)元组插入堆中。但是,如果值在比较时抛出异常,那么这将不起作用(它们将在键之间进行比较时进行比较)。
第二个选项是在类中定义一个__lt__
(小于)方法,该方法将使用适当的属性来比较元素以进行排序。但是,如果对象是由另一个包创建的,或者如果您需要它们在程序的其他地方进行不同的比较,那么这可能是不可能的。
第三种选择是使用sortedlist模块中的blist类(免责声明:我是作者)。 sortedlist
的构造函数使用key
参数,该参数允许您指定一个函数来返回元素的排序键,类似于key
的{{1}}参数和{{1 }}
答案 4 :(得分:0)
您可以实现堆指令。请注意使用popitem()来获得优先级最低的项目。
import heapdict as hd
import string
import numpy as np
h = hd.heapdict()
keys = [char for char in string.ascii_lowercase[:10]]
vals = [i for i in np.random.randint(0,10, 10)]
for k,v in zip(keys,vals):
h[k] = v
for i in range(len(vals)):
print h.popitem()
答案 5 :(得分:0)
我有同样的问题,但以上答案均未达到目的,尽管有些答案很接近,但不够详尽。无论如何,我做了一些研究并尝试了这段代码,希望这对于接下来想要得到答案的人来说应该足够了:
使用元组的问题是它仅使用不太灵活的第一项。我想要类似于c ++中的std :: priority_queue的东西,如下所示:
std::priority_queue<pair<int, int>, vector<pair<int, int>>, comparator> pq;
在这里我可以设计自己的比较器,这在现实应用中更常见。
希望以下摘录有助于您: https://repl.it/@gururajks/EvenAccurateCylinders
import heapq
class PQNode:
def __init__(self, key, value):
self.key = key
self.value = value
# compares the second value
def __lt__(self, other):
return self.value < other.value
def __str__(self):
return str("{} : {}".format(self.key, self.value))
input = [PQNode(1, 4), PQNode(7, 4), PQNode(6, 9), PQNode(2, 5)]
hinput = []
for item in input:
heapq.heappush(hinput, item)
while (hinput):
print (heapq.heappop(hinput))
答案 6 :(得分:0)
我觉得最简单的方法是重写heapq模块的现有cmp_lt函数。一个简短的例子:
import heapq
# your custom function. Here, comparing tuples a and b based on their 2nd element
def new_cmp_lt(self,a,b):
return a[1]<b[1]
#override the existing "cmp_lt" module function with your function
heapq.cmp_lt=new_cmp_lt
#Now use everything like normally used