如何使heapq评估特定属性的堆?

时间:2010-10-17 18:06:27

标签: python data-structures heap

我希望拥有一堆物品,而不仅仅是数字。它们将具有一个整数属性,堆可以按其排序。在python中使用堆的最简单方法是heapq,但在使用heapq时如何告诉它按特定属性排序?

7 个答案:

答案 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