数字だけでなく、たくさんの物を持っていきたいです。それらには、ヒープがソートできる整数属性が含まれます。Pythonでヒープを使用する最も簡単な方法はheapqですが、heapqを使用するときに特定の属性で並べ替えるように指示するにはどうすればよいですか?
8 に答える
ドキュメントの例によると、タプルを使用でき、タプルの最初の要素で並べ替えられます。
>>> 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__
場合は、プッシュ時に手動で並べ替えキーを抽出できます。
タプルのペアの最初の要素が等しい場合、さらに要素が比較されることに注意してください。これが希望どおりでない場合は、最初の各要素が一意であることを確認する必要があります。
heapq
オブジェクトを同じ方法で並べ替えるので、クラス定義内list.sort
でメソッドを定義するだけ__cmp__()
で、同じクラスの別のインスタンスと比較されます。
def __cmp__(self, other):
return cmp(self.intAttribute, other.intAttribute)
Python2.xで動作します。
3.xでの使用:
def __lt__(self, other):
return self.intAttribute < other.intAttribute
公式文書によると、これに対する解決策は、エントリをタプルとして保存することです(セクション8.4.1および8.4.2を参照してください)。
たとえば、オブジェクトはタプルの形式 (key、value_1、value_2)で次のようになります。
オブジェクト(つまりタプル)をヒープに入れると、オブジェクトの最初の属性(この場合は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()
最も簡単な方法は、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
私は同じ質問をしましたが、いくつかは近くにありましたが、十分に詳しく説明されていませんでしたが、上記の答えはどれもその場に出ませんでした。とにかく、私はいくつかの調査を行い、このコードを試しました。うまくいけば、これは答えを得ようとしている次の誰かにとって十分なはずです。
タプルを使用する際の問題は、柔軟性があまり高くない最初のアイテムのみを使用することです。次のような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))
残念ながら、これは頻繁に要求される機能ですが、できません。
1つのオプションは、(キー、値)タプルをヒープに挿入することです。ただし、比較時に値が例外をスローした場合は機能しません(キーが同点の場合は比較されます)。
2番目のオプションは__lt__
、適切な属性を使用して要素を比較して並べ替える(未満の)メソッドをクラスに定義することです。ただし、オブジェクトが別のパッケージによって作成された場合、またはプログラムの他の場所で異なる方法で比較する必要がある場合は、それが不可能な場合があります。
3番目のオプションは、 blistモジュールのsortedlistクラスを使用することです(免責事項:私は作成者です)。のコンストラクターは、およびのパラメーターと同様に、要素のソートキーを返す関数を指定できるパラメーターを取ります。sortedlist
key
key
list.sort
sorted
ヒープディクトを実装できます。最も優先度の低いアイテムを取得するために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()
と呼ばれるモジュールがありますheaps
。Githubアドレスはhttps://github.com/gekco/heapyです。クラスのインスタンス化時または配列からヒープを作成するときに、独自のキー/ソート関数を適用できます。これにより、アクションを実行するたびに引数としてヒープを追加する手間が省けます。
タプルの最後の位置にある最小の要素がヒープの一番上にあるリストが必要な例:
>>> from heapy.heap import Heap
>>> a = [(3, 5, 10), (-5, 3, 8), (7, 8, 9), (-4, 0, 2)]
>>> x = Heap.from_array(a, key=lambda t : t[-1])
>>> x.length
4
>>> x.top()
(-4, 0, 2)
>>> x.insert((-1, 0, 1))
>>> x.length
5
>>> x.top()
(-1, 0, 1)
>>> a
[(3, 5, 10), (-5, 3, 8), (7, 8, 9), (-4, 0, 2)]