Swift में ऐरे को सही तरीके से कैसे शफल करें: शुरुआत से विशेषज्ञ तक
\nक्या आपने कभी सोचा है कि अपने ऐप में रैंडम प्लेलिस्ट कैसे बनाएं? या हो सकता है, आपको क्विज़ में प्रश्नों को शफल करने की आवश्यकता हो, ताकि वे हर बार नए क्रम में आएं? यदि आप Swift के साथ काम करते हैं, तो देर-सबेर आपको इस कार्य का सामना करना पड़ेगा: ऐरे को कैसे शफल करें (shuffle array)। Stack Overflow पर इस प्रश्न को हज़ारों बार देखा गया है, और यह उचित भी है—यहाँ पहली नज़र में लगने से कहीं अधिक छिपी समस्याएं हैं।
\nइस लेख में, हम केवल shuffle() को कॉल करना नहीं दिखाएंगे। हम हुड के नीचे देखेंगे: एल्गोरिदम को समझेंगे, प्रदर्शन की तुलना करेंगे, ऑप्टिमाइज़्ड शफलिंग करना सीखेंगे और समझेंगे कि मानक विधि कब बुरी है और कब यह मानवता का सबसे अच्छा आविष्कार है। चलिए शुरू करते हैं!
सिर्फ "random" एक बुरा विचार क्यों है?
\nमान लीजिए, आपके पास एक ऐरे है:
\nvar cards = ["इक्का", "बादशाह", "रानी", "गुलाम"]\nसबसे सरल तरीका एक नया ऐरे बनाना और तत्वों को यादृच्छिक स्थानों पर डालना है। यह तार्किक लगता है, है ना?
\nfunc 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 मिलियन। ऐप "लैग" करने लगेगा, उपयोगकर्ता चला जाएगा, रेटिंग गिर जाएगी। ऐसा न करें।
बिल्ट-इन विधि shuffle(): आपका नया सबसे अच्छा दोस्त
\nSwift 4.2 से शुरू करके, हमारे पास मूल विधि shuffle() (परिवर्तनीय ऐरे के लिए) और shuffled() (नया ऐरे लौटाता है) है। यह इस प्रकार काम करता है:
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आइए इसे मैन्युअल रूप से लागू करें ताकि जादू को समझ सकें:
\nextension 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 के मानक कार्यान्वयन पर भरोसा करें—यह इष्टतम है।