Swift में ऐरे को कैसे शफल करें: ऑप्टिमाइज़ेशन और प्रदर्शन

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

Swift में ऐरे को सही तरीके से कैसे शफल करें: शुरुआत से विशेषज्ञ तक

\n

क्या आपने कभी सोचा है कि अपने ऐप में रैंडम प्लेलिस्ट कैसे बनाएं? या हो सकता है, आपको क्विज़ में प्रश्नों को शफल करने की आवश्यकता हो, ताकि वे हर बार नए क्रम में आएं? यदि आप Swift के साथ काम करते हैं, तो देर-सबेर आपको इस कार्य का सामना करना पड़ेगा: ऐरे को कैसे शफल करें (shuffle array)। Stack Overflow पर इस प्रश्न को हज़ारों बार देखा गया है, और यह उचित भी है—यहाँ पहली नज़र में लगने से कहीं अधिक छिपी समस्याएं हैं।

\n

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

\n\n

सिर्फ "random" एक बुरा विचार क्यों है?

\n

मान लीजिए, आपके पास एक ऐरे है:

\n
var cards = ["इक्का", "बादशाह", "रानी", "गुलाम"]
\n

सबसे सरल तरीका एक नया ऐरे बनाना और तत्वों को यादृच्छिक स्थानों पर डालना है। यह तार्किक लगता है, है ना?

\n
func naiveShuffle(_ array: [String]) -> [String] {\n    var shuffled = [String]()\n    for element in array {\n        let randomIndex = Int.random(in: 0...shuffled.count)\n        shuffled.insert(element, at: randomIndex)\n    }\n    return shuffled\n}
\n

छोटे ऐरे (4-10 तत्व) पर यह काम करता है। लेकिन जैसे ही तत्वों की संख्या सौ से अधिक होती है, आपको दर्द महसूस होगा। क्यों? क्योंकि insert(at:) की जटिलता O(n) है—हर बार जब आप शुरुआत या बीच में कोई तत्व डालते हैं, तो बाद के सभी तत्व शिफ्ट हो जाते हैं। अंतिम जटिलता: O(n²)। 1000 तत्वों वाले ऐरे के लिए यह 500,000 ऑपरेशन हैं। 10,000 के लिए—पहले से ही 50 मिलियन। ऐप "लैग" करने लगेगा, उपयोगकर्ता चला जाएगा, रेटिंग गिर जाएगी। ऐसा न करें।

\n\n

बिल्ट-इन विधि shuffle(): आपका नया सबसे अच्छा दोस्त

\n

Swift 4.2 से शुरू करके, हमारे पास मूल विधि shuffle() (परिवर्तनीय ऐरे के लिए) और shuffled() (नया ऐरे लौटाता है) है। यह इस प्रकार काम करता है:

\n
var numbers = [1, 2, 3, 4, 5]\nnumbers.shuffle()  // मूल ऐरे को बदलता है\nprint(numbers)     // उदाहरण: [3, 1, 5, 2, 4]\n\nlet shuffledNumbers = numbers.shuffled()  // नया ऐरे\nprint(shuffledNumbers)                    // [4, 2, 1, 5, 3]
\n

हुड के नीचे, Apple फिशर-येट्स एल्गोरिदम (जिसे नुथ एल्गोरिदम भी कहा जाता है) का उपयोग करता है। यह शफलिंग का स्वर्ण मानक है। यह कैसे काम करता है? हम ऐरे के अंतिम तत्व से पहले तक जाते हैं, प्रत्येक के लिए 0 से वर्तमान स्थिति तक एक यादृच्छिक इंडेक्स चुनते हैं और तत्वों को आपस में बदलते हैं। जटिलता: O(n)। 10,000 तत्वों वाले ऐरे के लिए—केवल 10,000 ऑपरेशन। सरल दृष्टिकोण से 5000 गुना तेज़!

\n\n

फिशर-येट्स एल्गोरिदम: सरल भाषा में समझ

\n

आइए इसे मैन्युअल रूप से लागू करें ताकि जादू को समझ सकें:

\n
extension Array {\n    mutating func customShuffle() {\n        for i in stride(from: count - 1, through: 1, by: -1) {\n            let j = Int.random(in: 0...i)\n            swapAt(i, j)\n        }\n    }\n}\n\nvar deck = Array(1...10)\ndeck.customShuffle()\nprint(deck) // [6, 2, 9, 1, 8, 4, 7, 3, 10, 5]
\n

यहाँ क्या हो रहा है? मान लीजिए, 5 तत्वों का एक ऐरे है। हम इंडेक्स 4 (अंतिम) से शुरू करते हैं। 0 से 4 तक एक यादृच्छिक संख्या चुनते हैं, आपस में बदलते हैं। फिर इंडेक्स 3 पर जाते हैं, 0 से 3 तक चुनते हैं, बदलते हैं। और इसी तरह इंडेक्स 1 तक। प्रत्येक तत्व एक यादृच्छिक स्थान पर ठीक एक बार आने की गारंटी है। कोई शिफ्ट नहीं, कोई बार-बार डालना नहीं—शुद्ध गणित।

\n

एक महत्वपूर्ण बारीकियां: फिशर-येट्स एल्गोरिदम में, प्रत्येक चरण पर 0 से count-1 तक यादृच्छिक इंडेक्स चुनना संभव नहीं है। क्यों? क्योंकि तब कुछ तत्व अपने स्थान पर रह सकते हैं, जबकि अन्य कई बार स्थानांतरित हो सकते हैं, जो वितरण की एकरूपता को बिगाड़ देगा। Apple के मानक कार्यान्वयन पर भरोसा करें—यह इष्टतम है।

ब्लॉग

पुस्तक अनुशंसाएँ