दिलचस्प पोस्ट
पिकासो लाइब्रेरी के साथ अपना स्वयं का डिस्क कैश कैसे लागू करें – एंड्रॉइड? रेल 3 में 'config.autoload_paths' में लिब जोड़ना मेरे मॉड्यूल को स्वत: लोड नहीं करता है जावा 8: लैम्ब्डा एक्सप्रेशंस में हैंडलिंग अनिवार्य है। क्यों अनिवार्य है, वैकल्पिक नहीं? सीएसवी निर्यात करने के लिए jQuery तालिका वेबपेज पर कस्टम राइट-क्लिक मेनू कैसे जोड़ें? जावा के साथ विंडो के शीर्ष से एक डिवी के शीर्ष से दूरी निर्धारित करें पीडीएफबॉक्स के साथ एक अन्य PDPage के अंदर एक PDPage कैसे डालें सी # स्ट्रिंग.फ़ॉर्मेट के जावा समकक्ष () और स्ट्रिंग.जोन () जावा: System.out.println और System.err.println क्रम से बाहर जावास्क्रिप्ट – मूल्य से एक सरणी आइटम को हटा दें मैं विंडो में एक चर में एक कमांड के परिणाम कैसे प्राप्त करूं? सीएसएस के साथ स्क्रॉल पट्टी की स्थिति कैसे बदलनी है? विदेशी आर्किटेक्चर मानकों समितियों के बारे में परवाह है आप एक मोगूज़ दस्तावेज़ को एक सादे ऑब्जेक्ट में कैसे बदलते हैं? NSNotificationCenter के साथ ऑब्जेक्ट कैसे पास करें I

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

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

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

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

वेब के समाधान से एकत्रित समाधान "शब्दकोशों में आदेश और मनमाना क्यों सेट है?"

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

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

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

उदाहरण के लिए, 'foo' और 'bar' की चाबियाँ ले लीजिए, और मान लेते हैं कि टेबल आकार 8 स्लॉट है पायथन 2.7 में, hash('foo') है -4177197833195190597 9 -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 (सबसे अधिक इस्तेमाल किया अजगर implemenation) द्वारा उपयोग की जाने वाली अंतर्निहित संरचना के लिए तकनीकी नाम एक हैश तालिका है , एक है जो खुला पते का उपयोग करता है। यदि आप उत्सुक हैं, और अच्छी तरह से सी समझते हैं, तो सभी (अच्छी तरह से प्रलेखित) विवरणों के लिए सी कार्यान्वयन पर एक नज़र डालें। आप ब्रैंडन रोड्स के इस Pycon 2010 प्रस्तुति को देख सकते हैं कि कैसे सीपीथाऑन डिक्क काम करता है, या सुंदर कोड की एक प्रति उठाता है, जिसमें एंड्रयू कुचिंग द्वारा लिखित कार्यान्वयन के एक अध्याय शामिल हैं

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

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

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

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

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

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


अन्य सही हैं: आदेश पर भरोसा मत करो एक का नाटक भी मत करो

उस ने कहा, एक बात आप पर भरोसा कर सकते हैं:

 list(myset) == list(myset) 

यही है, ऑर्डर स्थिर है


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

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

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

  • नंबरों को कैसे धोया जाता है

ऊपर से:

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

इसमें एक बैकिंग सरणी है:

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

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

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

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

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

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

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

CPython के हैश सेट इस तरह से संग्रहीत हैं:

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

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

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

अंत में, hash(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 कुछ चीज़ों को देखकर काफी सरलता से लागू होता है: यह सूची में घुसता है और पहले एक पॉप करता है


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

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

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

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

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

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

जिस क्रम में बाइंडिंग लौटाया जाता है वह मनमाना हो सकता है

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

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

और कंप्यूटर साइंस

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

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

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

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

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

इसके लिए, पूर्णांक के हैश मान के रूप में पूर्णांक ही है * सूचकांक संख्या ( 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 

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

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

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

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

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

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


* कक्षा int लिए हैश फ़ंक्शन:

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