कस्टम के साथ heapq विधेय की तुलना करें


82

मैं एक कस्टम प्रकार विधेय के साथ एक ढेर बनाने की कोशिश कर रहा हूं। चूंकि इसमें जाने वाले मान 'उपयोगकर्ता-परिभाषित' प्रकार के हैं, इसलिए मैं उनकी अंतर्निहित तुलना विधेय को संशोधित नहीं कर सकता।

क्या कुछ करने का एक तरीका है:

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

या इससे भी बेहतर, मैं अपने स्वयं के कंटेनर में हीपैक कार्यों को लपेट सकता हूं, इसलिए मुझे विधेय को पारित करने की आवश्यकता नहीं है।



जवाबों:


120

हीप दस्तावेज़ीकरण के अनुसार , ढेर आदेश को अनुकूलित करने का तरीका यह है कि ढेर पर प्रत्येक तत्व एक टपल हो, पहला टपल तत्व एक है जो सामान्य पायथन तुलनाओं को स्वीकार करता है।

हीपेक मॉड्यूल में कार्य थोड़ा बोझिल होते हैं (क्योंकि वे ऑब्जेक्ट-ओरिएंटेड नहीं होते हैं), और हमेशा हमारे हीप ऑब्जेक्ट (एक ढेर सूची) को पहले पैरामीटर के रूप में स्पष्ट रूप से पारित करने की आवश्यकता होती है। हम एक साधारण रैपर क्लास बनाकर एक पत्थर से दो पक्षियों को मार सकते हैं जो हमें एक keyफ़ंक्शन को निर्दिष्ट करने और ढेर को एक वस्तु के रूप में प्रस्तुत करने की अनुमति देगा ।

नीचे दिया गया वर्ग एक आंतरिक सूची रखता है, जहां प्रत्येक तत्व एक टपल है, जिसमें से पहला सदस्य एक कुंजी है, जो keyपैरामीटर का उपयोग करके तत्व सम्मिलन समय पर गणना की जाती है , हीप तात्कालिकता में पारित किया गया है:

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

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

   def push(self, item):
       heapq.heappush(self._data, (self.key(item), self.index, item))
       self.index += 1

   def pop(self):
       return heapq.heappop(self._data)[2]

(अतिरिक्त self.indexहिस्सा झड़पों से बचने के लिए है जब मूल्यांकित कुंजी मान एक ड्रॉ है और संग्रहीत मूल्य सीधे तुलना करने योग्य नहीं है - अन्यथा टाइपकेयर के साथ हीपैक विफल हो सकता है)


4
बहुत अच्छा! आप आगे भी जा सकते हैं और त्रिगुणों (self.key (आइटम), आईडी, आइटम) का उपयोग कर सकते हैं, जहां आईडी एक पूर्णांक के रूप में संभाला जाने वाला पूर्णांक हो सकता है, और प्रत्येक पुश के बाद बढ़ा दिया जा सकता है। इस तरह, आप कुंजी (आइटम 1) = कुंजी (आइटम 2) के उठाए गए अपवाद से बचते हैं। क्योंकि चाबियां अनूठी होंगी।
1930 में ज़ीउस

4
मैंने वास्तव में इसे (या इस पर आधारित कुछ) को पायथन के स्टडलिब में धकेलने की कोशिश की, और सुझाव को अस्वीकार कर दिया गया।
1

1
दया, पायथन विशेषताओं के ऑब्जेक्ट-ओरिएंटेड शैली को फिट करता है, और मुख्य तर्क अतिरिक्त लचीलापन प्रदान करता है।
ज्यूकस

मैंने उदाहरण के लिए tuple के बजाय उदाहरण का उपयोग किया है [self.key (आइटम), id, आइटम] और यह तब तक ठीक काम करता है जब तक कि पहला सूचकांक कुंजी है।
दीपक यादव

5
यह विफल हो जाएगा यदि तत्व तुलनीय नहीं हैं और प्रमुख मूल्यों में संबंध हैं। मैं id(item)संबंधों को तोड़ने के लिए टपल के मध्य तत्व के रूप में रखूँगा।
जॉर्जी येंचेव

48

एक वर्ग को परिभाषित करें, जिसमें __lt__()फ़ंक्शन को ओवरराइड करें । नीचे उदाहरण देखें (पायथन 3.7 में काम करता है):

import heapq

class Node(object):
    def __init__(self, val: int):
        self.val = val

    def __repr__(self):
        return f'Node value: {self.val}'

    def __lt__(self, other):
        return self.val < other.val

heap = [Node(2), Node(0), Node(1), Node(4), Node(2)]
heapq.heapify(heap)
print(heap)  # output: [Node value: 0, Node value: 2, Node value: 1, Node value: 4, Node value: 2]

heapq.heappop(heap)
print(heap)  # output: [Node value: 1, Node value: 2, Node value: 2, Node value: 4]


4
यह अब तक का सबसे साफ समाधान लगता है!
रॉयमन्सन

पिछली दो टिप्पणियों से बिल्कुल सहमत हैं। यह अजगर 3. के लिए एक बेहतर, क्लीनर समाधान लगता है
Chiraz BenAbdelkader

इसके अलावा, यहाँ एक समान प्रश्न का बहुत समान समाधान है: stackoverflow.com/questions/2501457/…
चिराज़ बेनअल्देल्केर

1
मैंने __gt__इसके बजाय इसका उपयोग किया और यह काम करता है। इससे कोई फर्क नहीं पड़ता कि हम किस जादूई पद्धति का उपयोग करते हैं? मुझे कुछ भी नहीं मिल रहा है heapqप्रलेखन। शायद यह संबंधित है कि पायथन सामान्य रूप से तुलना कैसे करता है?
जोश क्लार्क ने

1
में तुलना करते समय heapq, पायथन __lt__()पहली बार दिखता है । यदि यह परिभाषित नहीं है, तो यह दिखेगा __gt__()। यदि न तो परिभाषित किया गया है, तो यह फेंकता है TypeError: '<' not supported between instances of 'Node' and 'Node'। यह दोनों को परिभाषित करने __lt__()और __gt__(), प्रत्येक में एक प्रिंट स्टेटमेंट रखने और __lt__()वापस आने की पुष्टि की जा सकती है NotImplemented
फैनचेन बाओ

19

Heapq प्रलेखन पता चलता ढेर तत्वों tuples जिसमें पहला तत्व प्राथमिकता है और सॉर्ट क्रम को परिभाषित करता है हो सकता है।

आपके प्रश्न के लिए अधिक प्रासंगिक, हालांकि, यह है कि प्रलेखन में नमूना कोड के साथ एक चर्चा शामिल है कि कोई समान स्थिरता और तत्वों के साथ समान प्राथमिकता (अन्य मुद्दों के बीच) की समस्याओं से निपटने के लिए अपने स्वयं के हाइपर आवरण कार्यों को कैसे लागू कर सकता है।

संक्षेप में, उनका समाधान यह है कि हेपेक में प्रत्येक तत्व प्राथमिकता के साथ एक ट्रिपल हो, एक प्रवेश संख्या और सम्मिलित होने वाला तत्व हो। एंट्री काउंट सुनिश्चित करता है कि समान प्राथमिकता वाले तत्वों को उसी क्रम में क्रमबद्ध किया गया है जिसे उन्होंने हीप में जोड़ा था।


यह सही समाधान है, दोनों नीलम और हेप्पुशपॉप सीधे tuples के साथ काम करते हैं
daisy

2

दोनों उत्तरों के साथ सीमा यह है कि वे संबंधों को संबंधों के रूप में मानने की अनुमति नहीं देते हैं। पहले में, इनपुट ऑर्डर की तुलना करके, आइटम की तुलना करके संबंधों को तोड़ दिया जाता है। यह केवल संबंधों को मजबूत होने देने के लिए तेज़ है, और यदि उनमें से बहुत सारे हैं तो यह एक बड़ा बदलाव ला सकता है। उपरोक्त और डॉक्स के आधार पर, यह स्पष्ट नहीं है कि क्या इसे हीपेक में प्राप्त किया जा सकता है। यह अजीब लगता है कि हीपैक एक कुंजी को स्वीकार नहीं करता है, जबकि एक ही मॉड्यूल में इससे प्राप्त फ़ंक्शन करते हैं।
पुनश्च: यदि आप पहली टिप्पणी में लिंक का अनुसरण करते हैं ("संभव डुप्लिकेट ...") ले को परिभाषित करने का एक और सुझाव है जो एक समाधान की तरह लगता है।


2
setattr(ListNode, "__lt__", lambda self, other: self.val <= other.val)

हीप में वस्तुओं के मूल्यों की तुलना करने के लिए इसका उपयोग करें

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.