Подтвердить что ты не робот

Как сделать heapq оценивать кучу определенного атрибута?

Я хочу держать кучу объектов, а не только чисел. Они будут иметь в них целочисленный атрибут, который куча может сортировать. Самый простой способ использовать кучи в python - heapq, но как я могу сказать, что он сортирует по определенному атрибуту при использовании heapq?

4b9b3361

Ответ 1

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

Ответ 2

В соответствии с примером из документации вы можете использовать кортежи и сортировать по первому элементу кортежа:

>>> 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__, вы можете вручную извлечь свой сортировочный ключ в момент времени.

Обратите внимание, что если первые элементы в паре кортежей равны, будут сравниваться другие элементы. Если это не то, что вы хотите, вам нужно убедиться, что каждый первый элемент уникален.

Ответ 3

Согласно Официальному документу, решение этой проблемы заключается в хранении записей в виде кортежей (см. Разделы 8.4.1 и 8.4.2).

Например, ваш объект выглядит примерно так в формате кортежа (ключ, значение_1, значение_2)

Когда вы помещаете объекты (то есть кортежи) в кучу, он сравнивает первый атрибут объекта (в данном случае это ключ) для сравнения. Если происходит связывание, куча будет использовать следующий атрибут (т.е. значение_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()

Ответ 4

К сожалению, вы не можете, хотя это часто запрашиваемая функция.

Один вариант - вставить (ключ, значение) кортежи в кучу. Однако это не будет работать, если значения генерируют исключение при сравнении (они будут сравниваться в случае связи между клавишами).

Второй вариант заключается в определении метода __lt__ (меньше) в классе, который будет использовать соответствующий атрибут для сравнения элементов для сортировки. Однако это может быть невозможно, если объекты были созданы другим пакетом или если вам нужно их сравнивать по-другому в другом месте программы.

Третий вариант заключается в использовании класса sortedlist из blist (отказ от ответственности: я автор). Конструктор для sortedlist принимает параметр key, который позволяет вам указать функцию для возврата ключа сортировки элемента, аналогичного параметру key list.sort и sorted.

Ответ 5

Вы могли бы реализовать heapdict. Обратите внимание на использование 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()

Ответ 6

У меня был тот же вопрос, но ни один из вышеперечисленных ответов не попал в точку, хотя некоторые были близки, но недостаточно проработаны. Во всяком случае, я провел некоторое исследование и попробовал этот кусок кода, и, надеюсь, этого будет достаточно для кого-то следующего, кто хочет получить ответ:

Проблема с использованием кортежа состоит в том, что он использует только первый элемент, который не очень гибок. Я хотел что-то похожее на std :: priority_queue в c++, например так: 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))