अजगर में सेट का 'विचित्र' आदेश


14

जब मैं पायथन 3.8.0 सूची को एक सेट में परिवर्तित करता हूं, तो परिणामी सेट ऑर्डर * गैर-तुच्छ तरीके से अत्यधिक संरचित होता है। इस संरचना को छद्म यादृच्छिक सूची से कैसे निकाला जा रहा है?


एक प्रयोग के भाग के रूप में, मैं एक यादृच्छिक सेट उत्पन्न कर रहा हूँ। मुझे यह देखकर आश्चर्य हुआ कि सेट पर साजिश रचने से अचानक सेट में अप्रत्याशित रैखिक संरचना दिखाई दी। इसलिए मुझे हैरान करने वाली दो बातें हैं - एक सेट रिजल्ट में कंवर्ट करने का एक ऑर्डर क्यों होता है * जो इस संरचना को उजागर करता है; और, कुछ हद तक छद्म यादृच्छिक सेट में यह "छिपी" संरचना क्यों है?

कोड:

X = [randrange(250) for i in range(30)]
print(X)
print(set(X))

उदाहरण के लिए, जो आउटपुट देता है

[238, 202, 245, 94, 111, 106, 148, 164, 154, 113, 128, 10, 196, 141, 69, 38, 106, 8, 40, 53, 160, 87, 85, 13, 38, 147, 204, 50, 162, 91]

{128, 8, 10, 141, 13, 147, 148, 154, 160, 162, 164, 38, 40, 50, 53, 196, 69, 202, 204, 85, 87, 91, 94, 106, 238, 111, 113, 245}

उपरोक्त सूची का एक प्लॉट ** अपेक्षा के अनुसार काफी यादृच्छिक लगता है:

बेतरतीब ढंग से बनाई गई सूची की वोल्फ्रमअल्फा साजिश

सेट की साजिश रचते समय (जैसा कि इसे आउटपुट में आदेश दिया गया है) सेट में मौजूद संरचना को प्रदर्शित करता है:

रैंडम सूची से सेट का वुल्फरामअल्फा प्लॉट

यह व्यवहार मेरी मशीन पर 100% सुसंगत है (नीचे दिए गए और अधिक उदाहरण) 250 और 30 के मान के साथ उपरोक्त कोड में उपयोग किया गया उदाहरण (मैंने जिस उदाहरण का उपयोग किया है वह चेरी नहीं है - यह सिर्फ पिछले एक भाग है)। इन मूल्यों को ट्यूनिंग कभी-कभी थोड़ा अलग संरचना में होता है (उदाहरण के लिए दो के बजाय तीन अंकगणितीय प्रगति *** का एक सबसेट)।

क्या यह अन्य लोगों की मशीनों पर प्रजनन योग्य है? बेशक, इस तरह की संरचना मौजूद है, एक गैर-महान छद्म यादृच्छिक संख्या पीढ़ी का संकेत है, लेकिन यह स्पष्ट नहीं करता है कि किसी सेट में परिवर्तित करना इस संरचना को कुछ अर्थों में 'अर्क' कैसे करेगा। जहां तक ​​मुझे जानकारी है, कोई औपचारिक गारंटी नहीं है कि सेट का ऑर्डर (जब एक सूची से परिवर्तित किया गया हो) नियतात्मक है (और भले ही यह हो, पृष्ठभूमि में कोई परिष्कृत ऑर्डर नहीं किया जा रहा है)। तो यह कैसे हो रहा है ?!


(*): मुझे पता है, सेट अनियंत्रित संग्रह हैं, लेकिन मेरा मतलब है "आदेश" इस अर्थ में कि, printस्टेटमेंट को कॉल करते समय , सेट कुछ क्रम में आउटपुट होता है जो लगातार अंतर्निहित सेट संरचना को उजागर करता है।

(**): ये भूखंड वोल्फ्राम अल्फा के हैं। दो और उदाहरण नीचे दिए गए हैं:

यहाँ छवि विवरण दर्ज करें

(***): 250 से 500 तक यादृच्छिक संख्याओं की सीमा को बदलते समय दो भूखंड:

यहाँ छवि विवरण दर्ज करें

जवाबों:


14

असल में, यह दो चीजों के कारण है:

  • अजगर में एक समूह को एक का उपयोग कर कार्यान्वित किया जाता है hashtable ,
  • पूर्णांक का हैश पूर्णांक ही होता है।

इसलिए, अनुक्रमणिका जो अंतर्निहित सरणी में दिखाई देती है, वह पूर्णांक मान द्वारा निर्धारित की जाएगी, अंतर्निहित सरणी की लंबाई modulo। इसलिए, जब आप एक सेट में एक आकस्मिक सीमा डालते हैं, तो पूर्णांक बढ़ते क्रम में रहना होगा:

>>> list(set(range(10000))) == list(range(10000))
True # this can't be an accident!

यदि आपके पास किसी सन्निहित सीमा से सभी संख्याएँ नहीं हैं, तो "modulo की लंबाई अंतर्निहित सारणी" भाग में इस प्रकार है:

>>> r = range(0, 50, 4)
>>> set(r)
{0, 32, 4, 36, 8, 40, 12, 44, 16, 48, 20, 24, 28}
>>> sorted(r, key=lambda x: x % 32)
[0, 32, 4, 36, 8, 40, 12, 44, 16, 48, 20, 24, 28]

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

अंत के पास एक ब्लिप को छोड़कर (क्योंकि संख्या 52 और 56 सेट में नहीं हैं), सीमा को दो अनुक्रमों में विभाजित किया गया है 0, 4, 8, ...और 32, 36, 40, ...जो वैकल्पिक है क्योंकि हैश, जो संख्याओं के मान स्वयं हैं, चुनने के लिए modulo 32 लिया जाता है सरणी में सूचकांक। टक्कर होते हैं; उदाहरण के लिए, 4 और 36 समान मोडुलो 32 हैं, लेकिन 4 को पहले सेट में जोड़ा गया था, इसलिए 36 अलग इंडेक्स पर समाप्त होता है।

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

यहाँ छवि विवरण दर्ज करें

इंटरलीव्ड सीक्वेंस की संख्या, उस श्रेणी की लंबाई के अनुपात में सेट के आकार पर निर्भर करती है, जिससे संख्याएँ सैंपल की जाती हैं, क्योंकि यह निर्धारित करता है कि रेंज की लंबाई "मॉडुलो" के दौरान हैशटेबल के अंतर्निहित सरणी की लंबाई "कितनी बार" घूमती है। यहां तीन इंटरएक्टिव अनुक्रमों के साथ एक उदाहरण दिया गया है 0, 6, 12, ..., 66, 72, 78, ...और 36, 42, 48, ...:

>>> set(range(0, 90, 6))
{0, 66, 36, 6, 72, 42, 12, 78, 48, 18, 84, 54, 24, 60, 30}

आह! यह बताते हैं (और अच्छी व्याख्या भी)!
— जॉन डॉन

और निश्चित रूप से, भूखंडों में इस पैटर्न का सेट में अंतर्निहित संरचना से कोई लेना-देना नहीं है (हम उम्मीद करेंगे कि यह पैटर्न मेरे उदाहरण के रूप में यादृच्छिक सूचियों के साथ भूखंडों में उत्पन्न होगा) ... मैं सिर्फ अप्रत्याशित पैटर्न द्वारा बहकाया गया था भूखंडों!
— जॉन डॉन

आप कैसे पाते हैं कि 30 अंतर्निहित सरणी की लंबाई है?
— मार्क स्नाइडर

@MarkSnyder यह पता चला है कि यह 32 है, जिसका मतलब है कि टकराव होते हैं, लेकिन आदेश उसी तरह है जैसे कि यह 30 modulo था।
— kaya3

2
@MarkSnyder सरणी को आकार दिया जाएगा यदि यह 2/3 से अधिक पूर्ण हो जाता है , क्योंकि हैशटेबल के प्रदर्शन में बहुत गिरावट आती है यदि आप सरणी को पूर्ण या लगभग-पूर्ण करते हैं।
— kaya3
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.