foreach इंडेक्स क्यों नहीं देता? और इसका समाधान क्या है?
\n\nक्या आपने कभी C# में foreach लूप लिखा और अचानक सोचा: "मुझे करंट एलिमेंट का नंबर चाहिए!"। आपका हाथ कीबोर्ड पर जाता है for (int i = 0; i < list.Count; i++) लिखने के लिए... रुकिए! क्या होगा अगर कलेक्शन IEnumerable है, जिसमें इंडेक्स ही नहीं है? या आप HashSet के साथ काम कर रहे हैं? तब पुराना अच्छा for लूप काम नहीं करेगा।
यह सवाल Stack Overflow पर बहुत लोकप्रिय है (लाखों व्यूज!)। और सही भी है। foreach कलेक्शन को ट्रैवर्स करने का राजा है: यह छोटा, सुरक्षित और किसी भी एन्यूमरेबल टाइप के साथ काम करता है। लेकिन इसकी कमी है—इसमें बिल्ट-इन काउंटर नहीं है। आज हम इसे ठीक करेंगे। मैं आपको foreach में इंडेक्स पाने के 4 सिद्ध तरीके दिखाऊंगा, उनके फायदे, नुकसान और परफॉरमेंस समझाऊंगा। चलिए शुरू करते हैं!
तरीका #1. क्लासिक: बाहरी काउंटर
\n\nसबसे आसान और सहज तरीका। लूप से पहले एक काउंटर वेरिएबल बनाएं और लूप के अंदर इसे बढ़ाएं।
\n\nList<string> fruits = new List<string>() { "सेब", "केला", "चेरी", "खरबूजा" };\nint index = 0;\nforeach (var fruit in fruits)\n{\n Console.WriteLine($"इंडेक्स {index}: {fruit}");\n index++;\n}\n\nफायदे:
\n- \n
- बेहद स्पष्ट। कोड एक सेकंड में पढ़ा जा सकता है। \n
- किसी अतिरिक्त लाइब्रेरी या LINQ की जरूरत नहीं। \n
- किसी भी
IEnumerableके साथ काम करता है। \n
नुकसान:
\n- \n
- काउंटर को डिक्लेयर और इन्क्रीमेंट करना न भूलें। \n
- अगर लूप के अंदर
continueहै, तो काउंटर फिर भी बढ़ेगा (क्या आप यही चाहते हैं?)। \n - नेस्टेड लूप में यह भ्रमित कर सकता है कि कौन सा index किस लूप का है। \n
यह तरीका स्विस आर्मी नाइफ की तरह है: भरोसेमंद, लेकिन बेसिक। 80% कामों के लिए यह काफी है।
\n\nतरीका #2. LINQ Select इंडेक्स के साथ: एक लाइन में सुंदरता
\n\nअगर आपको फंक्शनल स्टाइल पसंद है, तो LINQ मदद करेगा। Select() मेथड का एक ओवरलोड है जो एलिमेंट का इंडेक्स भी देता है।
List<string> fruits = new List<string>() { "सेब", "केला", "चेरी", "खरबूजा" };\n\nforeach (var (fruit, index) in fruits.Select((item, i) => (item, i)))\n{\n Console.WriteLine($"इंडेक्स {index}: {fruit}");\n}\n\nध्यान दें टपल डीकंस्ट्रक्शन को लूप के हेडर में ही इस्तेमाल किया गया है। यह आधुनिक C# (वर्जन 7.0 से) की सबसे खूबसूरत विशेषताओं में से एक है।
\n\nफायदे:
\n- \n
- कोड डिक्लेरेटिव हो जाता है: "कलेक्शन लो, हर एलिमेंट में उसका इंडेक्स जोड़ो"। \n
- काउंटर बाहर नहीं आता—यह LINQ के अंदर एनकैप्सुलेटेड है। \n
- अन्य LINQ मेथड्स के साथ अच्छी तरह से काम करता है। \n
नुकसान:
\n- \n
- टपल बनाने का थोड़ा ओवरहेड। 10,000 एलिमेंट तक यह ध्यान देने योग्य नहीं, लेकिन बड़ी लिस्ट के लिए महत्वपूर्ण हो सकता है। \n
System.Linqइम्पोर्ट करना जरूरी है। \n
यह तरीका उन लोगों के लिए है जो "क्लीन" कोड लिखते हैं। यह तब बहुत अच्छा है जब इंडेक्स लूप को कंट्रोल करने के लिए नहीं, बल्कि किसी दूसरे मेथड में भेजने के लिए चाहिए।
\n\nतरीका #3. ElementAt() के जरिए इंडेक्सर: जब कलेक्शन सिर्फ IEnumerable हो
\n\nकभी-कभी आपके पास सिर्फ IEnumerable होता है, बिना इंडेक्सर के, लेकिन आप नंबर के हिसाब से एलिमेंट प्राप्त करना चाहते हैं। तकनीकी रूप से आप ऐसा कर सकते हैं:
IEnumerable<string> fruits = new List<string>() { "सेब", "केला", "चेरी", "खरबूजा" };\n\nfor (int i = 0; i < fruits.Count(); i++) // ध्यान दें: यह खराब कोड है!\n{\n var fruit = fruits.ElementAt(i);\n Console.WriteLine($"इंडेक्स {i}: {fruit}");\n}\n\nरुकिए! ऐसा कभी न करें। Count() और ElementAt() IEnumerable के लिए O(n) में काम करते हैं। आपका लूप O(n²) यानी क्वाड्रेटिक कॉम्प्लेक्सिटी में बदल जाएगा। 1000 एलिमेंट पर भी यह धीमा होगा।