2012-01-16 10 views
43

私はカスタムソート述部でヒープを構築しようとしています。値は 'user-defined'型であるため、組み込みの比較述語は変更できません。heapq with custom compare predicate

ような何かする方法があります:

h = heapq.heapify([...], key=my_lt_pred) 
h = heapq.heappush(h, key=my_lt_pred) 

あるいはさらに良いが、私はそう、私は述語を渡しておく必要はありません。私自身の容器にheapq機能をラップでした。

+1

可能性のある複製http://stackoverflow.com/questions/679731/min-heap-in-python –

+0

可能な複製[heapqを特定の属性のヒープを評価する方法?](http:// stackoverflow .COM /質問/ 3954530 /ハウツー - メイクheapq - 評価 - - - - の固有の属性ヒープオフ) –

答えて

58

heapq documentationによれば、ヒープ順序をカスタマイズする方法は、ヒープ上の各要素をタプルにすることです。最初のタプル要素は通常のPython比較を受け入れるものです。

heapqモジュールの関数は少し面倒です(オブジェクト指向ではないため)、ヒープオブジェクト(ヒープリスト)を最初のパラメータとして明示的に渡す必要があります。我々はkey関数を指定し、オブジェクトとしてヒープを提示することができる非常に単純なラッパークラスを作成することで、2つの鳥を1つのストーンで殺すことができます。

以下のクラスは、各要素がヒープのインスタンスに渡さタプル、keyパラメータを使用して要素の挿入時に計算キー、された第1部材である内部リストを保持:

# -*- coding: utf-8 -*- 
import heapq 

class MyHeap(object): 
    def __init__(self, initial=None, key=lambda x:x): 
     self.key = key 
     if initial: 
      self._data = [(key(item), item) for item in initial] 
      heapq.heapify(self._data) 
     else: 
      self._data = [] 

    def push(self, item): 
     heapq.heappush(self._data, (self.key(item), item)) 

    def pop(self): 
     return heapq.heappop(self._data)[1] 
+0

と直接作品です!さらに進んで、トリプル(self.key(item)、id、item)を使用することもできます。idはクラス属性として扱われる整数で、各プッシュ後にインクリメントされます。こうすることで、key(item1)= key(item2)のときに発生する例外を回避できます。キーは一意であるためです。 – zeycus

+1

私はこれをPythonのstdlibにプッシュしようとしましたが、その提案は辞退しました。 – jsbueno

+0

残念ながら、ほとんどのPython機能のオブジェクト指向スタイルに適合し、key引数は余分な柔軟性を提供します。 – zeycus

6

heapq documentationヒープ要素は最初の要素が優先され、ソート順を定義するタプルであり得ることを示唆しています。

しかし、ドキュメントには、ソートの安定性と同等の優先度を持つ要素(他の問題も含む)に対応する独自のheapqラッパー関数を実装する方法のdiscussion with sample codeが含まれています。一言で言えば

、その溶液はheapqの各要素は、優先度、エントリ数と挿入される要素と三重であることです。エントリ数は、同じ優先度aを持つ要素がheapqに追加された順序でソートされるようにします。

+0

この正解は、heappushとheappushpopの両方が非常に素晴らしいタプル – daisy

1

両方の答えの制限は、ネクタイがネクタイとして扱われることを許さないということです。最初は、アイテムを比較することによってネクタイを壊し、2番目は入力順序を比較してネストします。それは単にネクタイをネクタイにするほうが速く、ネクタイが多い場合には大きな違いが生じます。上記およびドキュメントに基づいて、heapqでこれが達成できるかどうかは不明です。 heapqがキーを受け付けないのは奇妙に思えますが、同じモジュール内でキーから派生した関数は受け入れます。
P.S: あなたが最初のコメントにリンクをたどっている場合(「可能複製...」)ソリューションのように思えるルを定義する別の提案があります。