2010-08-23 10 views
14

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

नोट: एक समाधान जो मैं सोच सकता हूं कि पूरी तरह से पुनरावृत्ति उद्देश्य के लिए सूची की प्रतिलिपि बनाना और लूप के भीतर मूल सूची से तत्वों को निकालना है। मैं इससे निपटने का एक बेहतर तरीका ढूंढ रहा हूं।

+4

समुदाय विकी क्यों? – LukeH

उत्तर

14

List<T>ToArray() विधि बेहद इस परिदृश्य में मदद करता है का उपयोग करते समय:

List<MyClass> items = new List<MyClass>(); 
foreach (MyClass item in items.ToArray()) 
{ 
    if (/* condition */) items.Remove(item); 
} 

विकल्प फोरैच के बजाए लूप के लिए उपयोग करना है, लेकिन जब भी आप कोई तत्व हटाते हैं तो आपको इंडेक्स वैरिएबल कम करना होगा यानी

List<MyClass> items = new List<MyClass>(); 
for (int i = 0; i < items.Count; i++) 
{ 
    if (/* condition */) 
    { 
     items.RemoveAt(i); 
     i--; 
    } 
} 
+0

यदि आप 'सूची ' का उपयोग कर रहे हैं तो इस परिदृश्य के लिए अंतर्निहित 'RemoveAll' विधि का उपयोग क्यों न करें? – LukeH

+0

मैं उन तरीकों का उपयोग करने से दूर हूं जो प्रतिनिधियों को उनके पैरामीटर के रूप में लेते हैं, क्योंकि आपको या तो एक नई विधि बनाना है या वर्तमान ब्लॉक में अनाम विधि जोड़ना है। यदि आप ऐसा करते हैं, तो आपका कोड डिबगिंग के दौरान संपादन और जारी रखने के साथ असंगत हो जाता है। –

+3

ToArray() में अनावश्यक प्रतिलिपि क्यों? –

1

अनुशंसित समाधान उन सभी तत्वों को रखना है जिन्हें आप एक अलग सूची में निकालना चाहते हैं और पहले लूप के बाद, एक दूसरा लूप डालें जहां आप निकालें-सूची पर पुन: प्रयास करते हैं और उन तत्वों को पहली सूची बनाते हैं।

+3

किसके द्वारा अनुशंसित? यह कोई लाभ के लिए, एक निर्विवाद रूप से महंगा दृष्टिकोण है। –

4

को एक नई सूची से आइटम को छान कर प्रारंभिक सूची को बदलने के लिए LINQ इस्तेमाल कर सकते हैं: लूप बारे में चिंता करने

IEnumerable<Foo> initialList = FetchList(); 
initialList = initialList.Where(x => SomeFilteringConditionOnElement(x)); 
// Now initialList will be filtered according to the condition 
// The filtered elements will be subject to garbage collection 

इस तरह से आप की जरूरत नहीं है।

+4

या, यदि सूची 'सूची ' है तो आप 'RemoveAll' विधि का उपयोग कर सकते हैं। – LukeH

+0

@LukeH, अच्छा बिंदु। –

5

आप आइटम हटाने के लिए पूर्णांक अनुक्रमण का उपयोग कर सकते हैं:

List<int> xs = new List<int> { 1, 2, 3, 4 }; 
for (int i = 0; i < xs.Count; ++i) 
{ 
    // Remove even numbers. 
    if (xs[i] % 2 == 0) 
    { 
     xs.RemoveAt(i); 
     --i; 
    } 
} 

यह हालांकि, बनाए रखने के लिए पढ़ने के लिए अजीब और कठिन हो सकता है, खासकर अगर पाश में तर्क किसी भी और अधिक जटिल हो जाता है।

13

अपनी सूची एक वास्तविक List<T> तो आप में निर्मित एक विधेय के आधार पर आइटम हटाने के लिए RemoveAll विधि का उपयोग कर सकते है:

int numberOfItemsRemoved = yourList.RemoveAll(x => ShouldThisItemBeDeleted(x)); 
+0

+1 निश्चित रूप से सबसे आसान तरीका है! – Abel

+0

यह विधि मानती है कि आपके पास एक प्रकार का फ़िल्टर है। उपयोगी नहीं है जब आप सवाल नहीं करते हैं। –

+0

@ लॉर्ड ब्लैक: सवाल विशेष रूप से कहता है कि वस्तुओं को "कुछ स्थितियों के आधार पर _" हटाया जाना चाहिए; मेरा hypothetical 'ShouldThisItemBeDeleted' फ़ंक्शन उन स्थितियों की अभिव्यक्ति होगी। – LukeH

0

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

यदि आपको लिंक और लैम्डा एक्सप्रेशन पसंद है तो मैं डारिन डिमिट्रोव समाधान की सिफारिश करूंगा, अन्यथा मैं क्रिस श्मीच द्वारा प्रदान किए गए समाधान का उपयोग करूंगा।

2

एक और चाल पीछे की सूची के माध्यम से लूप करना है .. किसी आइटम को हटाने से आप किसी भी प्रकार के लूप में सामना करने वाले किसी भी आइटम को प्रभावित नहीं करेंगे।

हालांकि मैं इस या किसी और चीज की सिफारिश नहीं कर रहा हूं। आपको जो कुछ भी चाहिए, वह शायद आपकी आवश्यकताओं पर सूची फ़िल्टर करने के लिए LINQ कथन का उपयोग करके किया जा सकता है।

0

आप foreach के साथ इस तरह से पुनरावृति कर सकते हैं:

List<Customer> custList = Customer.Populate(); 

foreach (var cust in custList.ToList()) 

{ 

     custList.Remove(cust); 

} 

नोट: चर की सूची पर ToList, ToList द्वारा बनाई गई सूची के माध्यम से इस दोहराता लेकिन मूल सूची से आइटम को हटा।

उम्मीद है कि इससे मदद मिलती है।