शब्दकोशों और सेटों में आदेश मनमाना क्यों है?


151

मुझे समझ में नहीं आता है कि एक शब्दकोष में लूपिंग करना या अजगर में सेट करना 'मनमाना' क्रम से कैसे होता है।

मेरा मतलब है, यह एक प्रोग्रामिंग भाषा है इसलिए भाषा में सब कुछ 100% निर्धारित किया जाना चाहिए, सही है? पायथन में कुछ प्रकार का एल्गोरिदम होना चाहिए जो यह तय करता है कि शब्दकोश या सेट का कौन सा हिस्सा चुना गया है, 1, दूसरा और इसी तरह।

मैं क्या खो रहा हूँ?


1
नवीनतम PyPy बिल्ड (2.5, पायथन 2.7 के लिए) डिफ़ॉल्ट रूप से ऑर्डर किए गए शब्दकोश बनाता है ।
विड्रैक

जवाबों:


236

नोट: यह उत्तर dictपायथन 3.6 में, परिवर्तित प्रकार के कार्यान्वयन से पहले लिखा गया था । इस उत्तर में अधिकांश कार्यान्वयन विवरण अभी भी लागू होते हैं, लेकिन शब्दकोशों में कुंजियों का लिस्टिंग क्रम हैश मानों द्वारा निर्धारित नहीं किया जाता है। सेट कार्यान्वयन अपरिवर्तित रहता है।

आदेश मनमाना नहीं है, लेकिन शब्दकोश या सेट के सम्मिलन और विलोपन इतिहास पर निर्भर करता है, साथ ही विशिष्ट पायथन कार्यान्वयन पर भी निर्भर करता है। इस उत्तर के शेष भाग के लिए, 'शब्दकोश' के लिए, आप 'सेट' भी पढ़ सकते हैं; सेट केवल कुंजियों और कोई मान के साथ शब्दकोशों के रूप में लागू किए जाते हैं।

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

स्लॉट्स पर सामग्री छोरों को सूचीबद्ध करना, और इसलिए कुंजी को उस क्रम में सूचीबद्ध किया गया है जो वे वर्तमान में तालिका में रहते हैं।

चाबियाँ ले लो 'foo'और 'bar'उदाहरण के लिए, और यह मान तालिका आकार 8 स्लॉट है की सुविधा देता है। पायथन 2.7 में, hash('foo')है -4177197833195190597, hash('bar')है 327024216814240868। मोडुलो 8, इसका मतलब है कि इन दो कुंजियों को स्लॉट 3 और 4 में स्लॉट किया गया है:

>>> hash('foo')
-4177197833195190597
>>> hash('foo') % 8
3
>>> hash('bar')
327024216814240868
>>> hash('bar') % 8
4

यह उनके लिस्टिंग क्रम को सूचित करता है:

>>> {'bar': None, 'foo': None}
{'foo': None, 'bar': None}

3 और 4 को छोड़कर सभी स्लॉट खाली हैं, पहले टेबल 3 पर सूचीबद्ध है, फिर स्लॉट 4 पर लूपिंग है, इसलिए 'foo'पहले सूचीबद्ध किया गया है 'bar'

barऔर baz, हालांकि, हैश मान हैं जो ठीक 8 अलग हैं और इस प्रकार सटीक उसी स्लॉट में मैप करते हैं 4:

>>> hash('bar')
327024216814240868
>>> hash('baz')
327024216814240876
>>> hash('bar') % 8
4
>>> hash('baz') % 8
4

उनका आदेश अब इस बात पर निर्भर करता है कि किस कुंजी को पहले स्लॉट किया गया था; दूसरी कुंजी को अगले स्लॉट में ले जाना होगा:

>>> {'baz': None, 'bar': None}
{'bar': None, 'baz': None}
>>> {'bar': None, 'baz': None}
{'baz': None, 'bar': None}

टेबल ऑर्डर यहां अलग है, क्योंकि पहले एक या दूसरी कुंजी को स्लॉट किया गया था।

सीपीथॉन द्वारा प्रयुक्त अंतर्निहित संरचना का तकनीकी नाम (सबसे अधिक इस्तेमाल किया जाने वाला पायथन अनुकरण) एक हैश तालिका है , जो कि खुले पते का उपयोग करता है। यदि आप उत्सुक हैं, और सी को अच्छी तरह से समझते हैं, तो सभी (अच्छी तरह से प्रलेखित) विवरणों के लिए सी कार्यान्वयन पर एक नज़र डालें । CPython कैसे काम करता है, या सुंदर कोड की एक प्रति लेने के बारे में ब्रैंडन रोड्स की इस Pycon 2010 प्रस्तुति को आप देख भी सकते हैं , जिसमें एंड्रयू कुचलिंग द्वारा लिखित कार्यान्वयन पर एक अध्याय भी शामिल है।dict

ध्यान दें कि पायथन 3.3 के रूप में, एक यादृच्छिक हैश बीज का उपयोग किया जाता है, कुछ प्रकार की सेवा से इनकार करने के लिए हैश टकराव को अप्रत्याशित बना देता है (जहां एक हमलावर बड़े पैमाने पर हैश टकराव के कारण एक पायथन सर्वर को अनुत्तरदायी बनाता है)। इसका मतलब यह है कि किसी दिए गए शब्दकोश या सेट का क्रम तब के पायथन आमंत्रण के लिए यादृच्छिक हैश बीज पर भी निर्भर है।

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

CPython 3.6 एक नया dict कार्यान्वयन प्रस्तुत करता है जो प्रविष्टि क्रम को बनाए रखता है, और बूट करने के लिए तेज़ और अधिक स्मृति कुशल है। एक बड़ी विरल तालिका रखने के बजाय जहां प्रत्येक पंक्ति संग्रहीत हैश मान, और कुंजी और मान ऑब्जेक्ट को संदर्भित करती है, नया कार्यान्वयन एक छोटा हैश सरणी जोड़ता है जो केवल एक अलग 'घने' तालिका में सूचकांकों को संदर्भित करता है (एक जिसमें केवल कई पंक्तियां होती हैं) जैसा कि वास्तविक कुंजी-मूल्य जोड़े हैं), और यह घनी तालिका है जो क्रम में निहित वस्तुओं को सूचीबद्ध करने के लिए होता है। अधिक विवरण के लिए अजगर-देव का प्रस्ताव देखें । ध्यान दें कि पायथन 3.6 में यह एक कार्यान्वयन विवरण माना जाता है, पायथन-द-लैंग्वेज यह निर्दिष्ट नहीं करती है कि अन्य कार्यान्वयन को ऑर्डर बनाए रखना है। यह पायथन 3.7 में बदल गया, जहां इस विवरण को भाषा विनिर्देश होने के लिए ऊंचा किया गया था ; किसी भी कार्यान्वयन के लिए पायथन 3.7 या नए के साथ ठीक से संगत होने के लिए इस आदेश-संरक्षण व्यवहार को कॉपी करना होगा । और स्पष्ट होना: यह परिवर्तन सेट पर लागू नहीं होता है, क्योंकि सेट में पहले से ही एक 'छोटी' हैश संरचना है।

पायथन 2.7 और नया भी एक OrderedDictवर्ग प्रदान करता है , इसका एक उपवर्ग dictप्रमुख आदेश रिकॉर्ड करने के लिए एक अतिरिक्त डेटा संरचना जोड़ता है। कुछ गति और अतिरिक्त मेमोरी की कीमत पर, यह वर्ग याद रखता है कि आपने किस क्रम में चाबियाँ डाली थीं; लिस्टिंग कुंजियाँ, मान या आइटम तब उस क्रम में ऐसा करेंगे। यह ऑर्डर को अद्यतित रखने के लिए एक अतिरिक्त शब्दकोश में संग्रहीत दोगुनी-लिंक सूची का उपयोग करता है। विचार को रेखांकित करते हुए रेमंड हेटिंगर की पोस्ट देखें । OrderedDictवस्तुओं के अन्य फायदे हैं, जैसे कि फिर से क्रमबद्ध होना

यदि आप एक ऑर्डर किया गया सेट चाहते हैं, तो आप osetपैकेज स्थापित कर सकते हैं ; यह पायथन 2.5 और उससे ऊपर पर काम करता है।


1
मुझे नहीं लगता कि अन्य पायथन कार्यान्वयन किसी भी तरह से हैश टेबल का उपयोग नहीं कर सकते हैं या किसी अन्य (हालांकि अब हैश टेबल को लागू करने के लिए विभिन्न तरीकों के अरबों हैं, इसलिए अभी भी कुछ स्वतंत्रता है)। तथ्य यह है कि शब्दकोशों का उपयोग करें __hash__और __eq__(और कुछ नहीं) व्यावहारिक रूप से एक भाषा की गारंटी है, न कि कार्यान्वयन विवरण।

1
@delnan: मुझे आश्चर्य है कि अगर आप अभी भी हैश और समानता के परीक्षण के साथ एक ब्रीटी का उपयोग कर सकते हैं .. तो मैं निश्चित रूप से किसी भी मामले में उस पर शासन नहीं कर रहा हूं। :-)
मार्टिन पीटर्स

1
यह निश्चित रूप से सही है, और मुझे गलत wrt व्यवहार्यता साबित होने में खुशी होगी, लेकिन मुझे कोई रास्ता नहीं दिखता है कि एक व्यापक अनुबंध की आवश्यकता के बिना कोई हैश टेबल को हरा सकता है। बीट्री में बेहतर औसत-केस प्रदर्शन नहीं होता है और न ही आपको सबसे खराब स्थिति देता है (हैश टक्कर अभी भी रैखिक खोज का मतलब है)। तो आप केवल बहुत से हैश के लिए बेहतर प्रतिरोध प्राप्त करते हैं neomg congruent (mod tablesize), और इसे संभालने के लिए कई अन्य शानदार तरीके हैं (जिनमें से कुछ का उपयोग किया जाता है dictobject.c) और एक BTree की तुलना में बहुत कम तुलना के साथ समाप्त होता है, यहां तक ​​कि सही खोजने की भी जरूरत है सबट्री।

@ डायलेन: मैं पूरी तरह से सहमत हूं; मैं सबसे अधिक चाहता था कि अन्य कार्यान्वयन विकल्पों की अनुमति न देने के लिए धराशायी हो।
मार्टिन पीटर्स

37

यह एक नकल के रूप में बंद होने से पहले पायथन 3.41 ए सेट के लिए अधिक प्रतिक्रिया है ।


अन्य सही हैं: आदेश पर भरोसा नहीं करते। वहाँ भी दिखावा मत करो एक है।

उस ने कहा, वहाँ है एक चीज है जिस पर आप भरोसा कर सकते हैं:

list(myset) == list(myset)

अर्थात्, आदेश है स्थिर है


समझ क्यों वहाँ एक है कथित आदेश को समझने के लिए कुछ चीजों को समझने की आवश्यकता है:

  • वह पायथन उपयोग करता है हैश सेट उपयोग करता है ,

  • कैसे CPython हैश सेट स्मृति में संग्रहीत किया जाता है और

  • कैसे नंबर मिलते हैं

ऊपर से:

हैश सेट वास्तव में तेजी से देखने के समय के साथ यादृच्छिक डेटा संग्रहीत करने की एक विधि है।

इसका एक बैकिंग ऐरे है:

# A C array; items may be NULL,
# a pointer to an object, or a
# special dummy object
_ _ 4 _ _ 2 _ _ 6

हम उस विशेष डमी ऑब्जेक्ट को अनदेखा करेंगे, जो केवल हटाने के लिए ही आसान है, क्योंकि हम इन सेटों से नहीं हटाएंगे।

वास्तव में तेजी से देखने के लिए, आप किसी वस्तु से हैश की गणना करने के लिए कुछ जादू करते हैं। एकमात्र नियम यह है कि दो वस्तुएं जो समान हैं उनमें समान हैश है। (लेकिन अगर दो वस्तुओं में एक ही हैश हो तो वे असमान हो सकते हैं।)

फिर आप सरणी लंबाई द्वारा मापांक लेते हुए सूचकांक बनाते हैं:

hash(4) % len(storage) = index 2

यह तत्वों तक पहुंचने के लिए वास्तव में तेज़ बनाता है।

हश्र केवल कहानी के अधिकांश हैं, जैसा कि hash(n) % len(storage)और hash(m) % len(storage)समान संख्या में परिणाम कर सकते हैं। उस स्थिति में, कई अलग-अलग रणनीतियाँ संघर्ष की कोशिश कर सकती हैं और हल कर सकती हैं। सीपीथॉन जटिल चीजों को करने से पहले 9 बार "रैखिक जांच" का उपयोग करता है, इसलिए यह स्लॉट के बाईं ओर दिखेगा पहले 9 स्थानों तक ।

सीपीथॉन के हैश सेट को इस तरह संग्रहीत किया जाता है:

  • एक हैश सेट 2/3 से अधिक पूर्ण नहीं हो सकता है । यदि 20 तत्व हैं और समर्थन सरणी 30 तत्वों की है, तो बैकिंग स्टोर बड़ा होने का आकार देगा। इसका कारण यह है कि आपको छोटे बैकिंग स्टोर के साथ अधिक बार टकराव मिलते हैं, और टकराव सब कुछ धीमा कर देते हैं।

  • बैकिंग स्टोर 4 की शक्तियों में आकार लेता है, 8 से शुरू होता है, बड़े सेट (50k तत्वों) को छोड़कर जो दो: (8, 32, 128, ...) की शक्तियों में आकार लेते हैं।

इसलिए जब आप एक सरणी बनाते हैं, तो बैकिंग स्टोर की लंबाई 8 होती है। जब यह 5 पूर्ण होता है और आप एक तत्व जोड़ते हैं, तो इसमें संक्षेप में 6 तत्व होंगे। 6 > ²⁄₃·8तो यह एक आकार को ट्रिगर करता है, और बैकिंग स्टोर चौगुनी आकार 32 के लिए।

अंत में, hash(n)केवल nसंख्याओं के लिए रिटर्न ( -1जो विशेष है) को छोड़कर ।


तो, चलो पहले एक को देखते हैं:

v_set = {88,11,1,33,21,3,7,55,37,8}

len(v_set)10 है, इसलिए सभी आइटम जोड़े जाने के बाद बैकिंग स्टोर कम से कम 15 (+1) है । 2 की प्रासंगिक शक्ति 32 है। इसलिए समर्थन स्टोर है:

__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __

हमारे पास है

hash(88) % 32 = 24
hash(11) % 32 = 11
hash(1)  % 32 = 1
hash(33) % 32 = 1
hash(21) % 32 = 21
hash(3)  % 32 = 3
hash(7)  % 32 = 7
hash(55) % 32 = 23
hash(37) % 32 = 5
hash(8)  % 32 = 8

इसलिए ये सम्मिलित करें:

__  1 __  3 __ 37 __  7  8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __
   33 ← Can't also be where 1 is;
        either 1 or 33 has to move

तो हम जैसे आदेश की उम्मीद करेंगे

{[1 or 33], 3, 37, 7, 8, 11, 21, 55, 88}

1 या 33 के साथ जो शुरू में कहीं और नहीं है। यह रैखिक जांच का उपयोग करेगा, इसलिए हमारे पास या तो होगा:

       ↓
__  1 33  3 __ 37 __  7  8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __

या

       ↓
__ 33  1  3 __ 37 __  7  8 __ __ 11 __ __ __ __ __ __ __ __ __ 21 __ 55 88 __ __ __ __ __ __ __

आप उम्मीद कर सकते हैं कि 33 वही होगा जो कि विस्थापित हो चुका है क्योंकि 1 पहले से ही था, लेकिन आकार बदलने के कारण जो सेट बनाया जा रहा है, वास्तव में ऐसा नहीं है। हर बार जब सेट का पुनर्निर्माण होता है, तो पहले से जोड़े गए आइटम प्रभावी रूप से फिर से व्यवस्थित हो जाते हैं।

अब आप देख सकते हैं क्यों

{7,5,11,1,4,13,55,12,2,3,6,20,9,10}

क्रम में हो सकता है। 14 तत्व हैं, इसलिए बैकिंग स्टोर कम से कम 21 + 1 है, जिसका अर्थ है 32:

__ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __

पहले 13 स्लॉट में 1 से 13 हैश। 20 स्लॉट 20 में जाता है।

__  1  2  3  4  5  6  7  8  9 10 11 12 13 __ __ __ __ __ __ 20 __ __ __ __ __ __ __ __ __ __ __

55 स्लॉट में जाता है hash(55) % 32जो 23 है:

__  1  2  3  4  5  6  7  8  9 10 11 12 13 __ __ __ __ __ __ 20 __ __ 55 __ __ __ __ __ __ __ __

अगर हमने इसके बजाय 50 को चुना, तो हम उम्मीद करेंगे

__  1  2  3  4  5  6  7  8  9 10 11 12 13 __ __ __ __ 50 __ 20 __ __ __ __ __ __ __ __ __ __ __

और लो और निहारना:

{1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 20, 50}
#>>> {1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 50, 20}

pop चीजों की नज़र से काफी सरलता से लागू किया जाता है: यह सूची का पता लगाता है और पहले वाले को पॉप करता है।


यह सभी कार्यान्वयन विवरण है।


17

"मनमाना" "गैर-निर्धारित" के समान नहीं है।

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

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


3
ध्यान दें कि शब्दकोश चलना का एक हिस्सा अच्छी तरह से परिभाषित किया गया है: किसी दिए गए शब्दकोश की कुंजियों, मूल्यों या वस्तुओं पर ध्यान देना, प्रत्येक एक ही क्रम में होगा, जब तक कि बीच में शब्दकोश में कोई बदलाव नहीं किया गया है। इसका मतलब है कि d.items()अनिवार्य रूप से समान है zip(d.keys(), d.values())। यदि किसी भी आइटम को शब्दकोश में जोड़ा जाता है, तो सभी दांव बंद हो जाते हैं। यह क्रम पूरी तरह से बदल सकता है (यदि हैश तालिका को आकार देने की आवश्यकता है), हालांकि अधिकांश समय आप नए आइटम को अनुक्रम में कुछ मनमाने स्थान पर बदल पाएंगे।
ब्लोकनाथ

6

इस प्रश्न के अन्य उत्तर उत्कृष्ट और अच्छी तरह से लिखे गए हैं। ओपी "कैसे" पूछता है जिसे मैं "कैसे वे" या "क्यों" के साथ दूर हो जाते हैं के रूप में व्याख्या करते हैं।

पायथन प्रलेखन का कहना है कि शब्दकोशों का आदेश नहीं दिया गया है क्योंकि पायथन शब्दकोश सार डेटा प्रकार साहचर्य सरणी को लागू करता है । जैसा वे कहते हैं

जिस क्रम में बाइंडिंग वापस की जाती है, वह मनमाना हो सकता है

दूसरे शब्दों में, एक कंप्यूटर विज्ञान का छात्र यह नहीं मान सकता है कि एक साहचर्य सरणी का आदेश दिया गया है। गणित में सेट के लिए भी यही सच है

एक सेट के तत्वों को सूचीबद्ध करने का क्रम अप्रासंगिक है

और कंप्यूटर विज्ञान

एक सेट एक अमूर्त डेटा प्रकार है जो किसी विशेष क्रम के बिना, कुछ मूल्यों को संग्रहीत कर सकता है

एक हैश तालिका का उपयोग करते हुए एक शब्दकोश को लागू करना एक कार्यान्वयन विवरण है जो दिलचस्प है कि इसमें समान रूप से सहयोगी सरणियों के रूप में है जहां तक ​​आदेश है।


1
आप मूल रूप से सही हैं, लेकिन यह थोड़ा करीब होगा (और "अनियंत्रित" कारण पर एक अच्छा संकेत दें) यह कहने के लिए कि यह एक एशोक सारणी के बजाय हैश तालिका का कार्यान्वयन है ।
दो-बिट अल्केमिस्ट

5

पायथन उपयोग हैश टेबलशब्दकोशों को संग्रहीत करने के लिए , इसलिए शब्दकोशों या अन्य चलने योग्य वस्तुओं में कोई क्रम नहीं है जो हैश तालिका का उपयोग करते हैं।

लेकिन हैश ऑब्जेक्ट में आइटम के सूचकांक के बारे में, अजगर निम्नलिखित कोड के आधार पर सूचकांक की गणना करता हैhashtable.c :

key_hash = ht->hash_func(key);
index = key_hash & (ht->num_buckets - 1);

इसके बाद, जैसा कि पूर्णांकों का हैश मान पूर्णांक ही होता है * सूचकांक संख्या पर आधारित होता है ( ht->num_buckets - 1एक स्थिर होता है) इसलिए बिटकॉइन द्वारा गणना की जाती है और बीच में (ht->num_buckets - 1)और संख्या में ही * (-1 के लिए उम्मीद है कि यह हैश -2 है ), और अन्य वस्तुओं के लिए उनके हैश मान के साथ।

setउस उपयोग-तालिका के साथ निम्नलिखित उदाहरण पर विचार करें :

>>> set([0,1919,2000,3,45,33,333,5])
set([0, 33, 3, 5, 45, 333, 2000, 1919])

हमारे पास संख्या के लिए 33:

33 & (ht->num_buckets - 1) = 1

कि वास्तव में यह है:

'0b100001' & '0b111'= '0b1' # 1 the index of 33

नोट इस मामले में (ht->num_buckets - 1)है 8-1=7या0b111

और इसके लिए 1919:

'0b11101111111' & '0b111' = '0b111' # 7 the index of 1919

और इसके लिए 333:

'0b101001101' & '0b111' = '0b101' # 5 the index of 333

अजगर हैश के बारे में अधिक जानकारी के लिए अजगर स्रोत कोड से निम्नलिखित उद्धरण पढ़ने के लिए अपना काम करें :

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

>>> map(hash, (0, 1, 2, 3))
  [0, 1, 2, 3]
>>> map(hash, ("namea", "nameb", "namec", "named"))
  [-1658398457, -1658398460, -1658398459, -1658398462]

यह जरूरी बुरा नहीं है! इसके विपरीत, आकार 2 ** i की तालिका में, निम्न-क्रम i बिट्स को प्रारंभिक तालिका सूचकांक के रूप में लेना बहुत तेज़ है, और एक सन्निहित रेंज की संख्याओं द्वारा अनुक्रमित किए गए dicts के लिए बिल्कुल भी कोई टक्कर नहीं है। जब चाबियां "लगातार" तार होती हैं, तो यह लगभग सच है। तो यह आम मामलों में बेहतर-से-यादृच्छिक व्यवहार देता है, और यह बहुत ही वांछनीय है।

OTOH, जब टकराव होते हैं, हैश तालिका के सन्निहित स्लाइस को भरने की प्रवृत्ति एक अच्छी टक्कर संकल्प रणनीति को महत्वपूर्ण बनाती है। केवल हैश कोड के अंतिम i बिट्स लेना भी असुरक्षित है: उदाहरण के लिए, सूची [i << 16 for i in range(20000)]को कुंजियों के समूह के रूप में मानें। चूंकि किट्स अपने स्वयं के हैश कोड होते हैं, और यह 2 * 15 के आकार का होता है, प्रत्येक हैश कोड के अंतिम 15 बिट्स सभी 0 होते हैं: वे सभी एक ही टेबल इंडेक्स में मैप करते हैं।

लेकिन असामान्य मामलों में खानपान सामान्य लोगों को धीमा नहीं करना चाहिए, इसलिए हम वैसे भी अंतिम i बिट्स लेते हैं। यह बाकी करने के लिए टकराव के संकल्प पर निर्भर है। यदि हम आम तौर पर उस कुंजी को ढूंढते हैं जिसे हम पहले प्रयास के लिए देख रहे हैं (और, यह पता चला है, तो हम आमतौर पर करते हैं - टेबल लोड फैक्टर 2/3 के तहत रखा जाता है, इसलिए संभावनाएं हमारे पक्ष में ठोस हैं), फिर यह प्रारंभिक सूचकांक गणना गंदगी को सस्ता रखने के लिए सबसे अच्छा समझ में आता है।


* वर्ग के लिए हैश फ़ंक्शन int:

class int:
    def __hash__(self):
        value = self
        if value == -1:
            value = -2
        return value


-1

पायथॉन 3.7 (और पहले से ही CPython 3.6 ) के साथ शुरू होकर , शब्दकोश आइटम उस क्रम में रहते हैं, जिसे उन्होंने डाला था


सेट के रूप में अच्छी तरह से सच है?
ल्यूसिड_ड्रीमर

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