web-dev-qa-db-ja.com

heapqに特定の属性のヒープを評価させる方法は?

数値だけでなく、オブジェクトのヒープを保持したいと考えています。それらには、ヒープがソートできる整数属性が含まれます。 python=でヒープを使用する最も簡単な方法はheapqですが、heapqを使用するときに特定の属性でソートするようにするにはどうすればよいですか?

42
coffee

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
_
62
eumiro

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__メソッドでは、プッシュ時にソートキーを手動で抽出できます。

タプルのペアの最初の要素が等しい場合、さらに要素が比較されることに注意してください。これが希望どおりでない場合は、最初の各要素が一意であることを確認する必要があります。

56
Jander

公式ドキュメント によると、これに対する解決策はエントリをタプルとして保存することです(セクションをご覧ください)8.4.1および8.4.2)。

たとえば、あなたのオブジェクトはTupleの形式(key、value_1、value_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()

10
Catbuilts

残念ながらできませんが、これはよくリクエストされる機能です。

1つのオプションは、(キー、値)タプルをヒープに挿入することです。ただし、値が比較時に例外をスローする場合は機能しません(キー間のタイの場合は比較されます)。

2番目のオプションは、適切な属性を使用して要素を並べ替えるために比較するクラスで__lt__(より小)メソッドを定義することです。ただし、オブジェクトが別のパッケージによって作成された場合、またはプログラムの他の場所でオブジェクトを別の方法で比較する必要がある場合は、それができない場合があります。

3番目のオプションは、 blist モジュールの sortedlist クラスを使用することです(免責事項:私は作成者です)。 sortedlistのコンストラクタは、list.sortおよびkeykeyパラメータと同様に、要素のソートキーを返す関数を指定できるsortedパラメータを取ります。

3

同じ質問がありましたが、上記の回答はどれも当てはまりませんでした。とにかく、私はいくつかの調査を行ってこのコードを試しましたが、うまくいけば、回答を得ようとしている次の人にはこれで十分でしょう:

タプルを使用する際の問題は、非常に柔軟ではない最初の項目のみを使用することです。次のような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))
3
Guru

最も簡単な方法は、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
2
Tushar Agarwal

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()
0
DanGoodrick