2012-01-09 23 views
9

अभी के लिए भीतर से आइटम को हटाने, सबसे अच्छा मैं के बारे में सोच सकता है:कुशलतापूर्वक 'foreach'

bool oneMoreTime = true; 
while (oneMoreTime) 
{ 
    ItemType toDelete=null; 
    oneMoreTime=false; 
    foreach (ItemType item in collection) 
    { 
     if (ShouldBeDeleted(item)) 
     { 
      toDelete=item; 
      break; 
     } 
    } 
    if (toDelete!=null) 
    { 
     collection.Remove(toDelete); 
     oneMoreTime=true; 
    } 
} 

मैं जानता हूँ कि मैं कम से कम एक अतिरिक्त चर यहाँ है, लेकिन मैं इसे शामिल की पठनीयता में सुधार करने के लिए एल्गोरिदम।

+0

के संभावित डुप्लिकेट (http://stackoverflow.com/questions/653596/how-to-conditionally-remove-items-from-a-net- [सशर्त एक .NET संग्रह से आइटम निकालने का तरीका] संग्रह) –

उत्तर

31

"RemoveAll" विधि सर्वोत्तम है।

एक अन्य आम तकनीक है:

var itemsToBeDeleted = collection.Where(i=>ShouldBeDeleted(i)).ToList(); 
foreach(var itemToBeDeleted in itemsToBeDeleted) 
    collection.Remove(itemToBeDeleted); 

एक अन्य आम तकनीक पाश "के लिए" एक का उपयोग करने के लिए, लेकिन यकीन है कि तुम जाओ बनाने है पीछे की ओर:

for (int i = collection.Count - 1; i >= 0; --i) 
    if (ShouldBeDeleted(collection[i])) 
     collection.RemoveAt(i); 

एक अन्य आम तकनीक को जोड़ने के लिए है आइटम जो नए संग्रह में हटाए जा रहे हैं:

var newCollection = new List<whatever>(); 
foreach(var item in collection.Where(i=>!ShouldBeDeleted(i)) 
    newCollection.Add(item); 

और अब आपके पास दो संग्रह हैं। एक तकनीक जिसे मैं विशेष रूप से पसंद करता हूं यदि आप दो संग्रहों के साथ समाप्त करना चाहते हैं तो अपरिवर्तनीय डेटा संरचनाओं का उपयोग करना है। एक अपरिवर्तनीय डेटा संरचना के साथ, किसी आइटम को "निकालना" डेटा संरचना को नहीं बदलता है; यह आपको एक नई डेटा संरचना देता है (यदि संभव हो तो पुराने से बिट्स का पुन: उपयोग करता है) जिसमें आपके द्वारा निकाली गई वस्तु नहीं है। अपरिवर्तनीय डेटा संरचनाओं के साथ आप बात तुम पर पुनरावृत्ति कर रहे हैं संशोधित कर रहे हैं नहीं, इसलिए कोई समस्या नहीं है:

var newCollection = oldCollection; 
foreach(var item in oldCollection.Where(i=>ShouldBeDeleted(i)) 
    newCollection = newCollection.Remove(item); 

या

var newCollection = ImmutableCollection<whatever>.Empty; 
foreach(var item in oldCollection.Where(i=>!ShouldBeDeleted(i)) 
    newCollection = newCollection.Add(item); 

और जब आप पूरा कर लें, आप दो संग्रह है। नए आइटम को हटा दिया गया है, पुराना एक जैसा ही था।

+0

क्या आपने कभी फोरैच का उपयोग करके 'रिवर्स' एक्सटेंशन का उपयोग किया है - मैं अभी यहां http://stackoverflow.com/a/10541025/706363 पर आया हूं? यह अधिक व्यापक रूप से उपयोग क्यों नहीं किया जाएगा? क्या कोई गंभीर प्रदर्शन प्रभाव या कुछ चल रहा है? – ppumkin

+0

@ppumkin: 'आईएनयूमेरेबल' के लिए 'रिवर्स' के कार्यान्वयन को लिखने का प्रयास करें जो' IList', 'ICollection' को लागू नहीं करता है, और इसी तरह। आपके कार्यान्वयन की स्मृति और समय प्रदर्शन क्या है? –

+0

मेरा कार्यान्वयन समय या संसाधन महत्वपूर्ण नहीं है। मैं एक सूची में लिंक में 'IEnumerable.Reverse 'एक्सटेंशन का उपयोग कर रहा हूं, और ऐसा लगता है कि' foreach' के भीतर ठीक काम करता है - मैं क्यों पूछता हूं, यह उदाहरण के लिए अधिक बार क्यों उपयोग नहीं किया जाता है, इन सभी के विपरीत (i से 0) इसके विपरीत में, आपके उत्तर में। रिवर्स एक्सटेंशन का उपयोग वैध विकल्प है? क्या आप इसे अपने उत्तर में जोड़ सकते हैं या क्या फ़ोरैच के साथ संयोजन में लिंक से रिवर्स एक्सटेंशन का उपयोग करने में कुछ गड़बड़ है? बस सोचा, कि आपकी राय आपके अनुभव के कारण अधिक वजन लेगी। – ppumkin

13

जैसे ही मैंने टाइपिंग समाप्त की, मुझे याद आया कि ऐसा करने के लिए लैम्ब्डा-तरीका है।

collection.RemoveAll(i=>ShouldBeDeleted(i)); 

बेहतर तरीका?

+2

बस एक एफवाईआई: इसे एक विधि समूह में परिवर्तित किया जा सकता है। collection.RemoveAll (ShouldBeDeleted)। – ahawker

1

लैम्ब्डा रास्ता अच्छा है। आप नियमित रूप से लूप का भी उपयोग कर सकते हैं, आप सूचियों को पुन: सक्रिय कर सकते हैं कि लूप के भीतर लूप के लिए उपयोग किया जाता है, फ़ोरैच लूप के विपरीत।

for (int i = collection.Count-1; i >= 0; i--) 
{ 
    if(ShouldBeDeleted(collection[i]) 
     collection.RemoveAt(i); 
} 

मुझे लगता है कि संग्रह संभालने हूँ एक ArrayList यहाँ है, कोड थोड़ी अलग है, तो आप एक अलग डेटा संरचना का उपयोग कर रहे हो सकता है।

1

आप foreach लूप के अंदर किसी संग्रह से नहीं हटा सकते हैं (जब तक कि यह एक विशेष गणक नहीं है)। संग्रहित होने पर बीसीएल संग्रह अपवाद फेंक देगा अगर गणना की जा रही है।

आप व्यक्तिगत तत्वों को हटाने और तदनुसार इंडेक्स को समायोजित करने के लिए for पाश का उपयोग कर सकते हैं। हालांकि, ऐसा करने से त्रुटि प्रवण हो सकती है। अंतर्निहित संग्रह के कार्यान्वयन के आधार पर व्यक्तिगत तत्वों को हटाना महंगा हो सकता है। उदाहरण के लिए List<T> के पहले तत्व को हटाने से सूची में सभी पुनर्निर्मित तत्वों की प्रतिलिपि बनाई जाएगी।

var newCollection = collection.Where(item => !ShouldBeDeleted(item)).ToList(); 

उपयोग ToList() या ToArray() नया संग्रह बनाने या IEnumerableWhere() खंड द्वारा लौटाए से अपने विशिष्ट संग्रह प्रकार प्रारंभ करने में:

सबसे अच्छा समाधान एक नया संग्रह वर्ष के आधार पर बनाने के लिए अक्सर है।

1

पिछड़े for पाश पर एक आगे भिन्नता:

for (int i = 0; i < collection.Count;) 
    if (ShouldBeDeleted(collection[i])) 
     collection.RemoveAt(i) 
    else 
     i++; 
0

बस

प्रथम सूची अपने मूल सूची और दूसरा सूची है दो सूची का उपयोग करें, जो आइटम नहीं निकाला जाना चाहिए के लिए है।

var filteredItems = new List<ItemType>(); 

foreach(var item in collection){ 
    if(!ShouldBeDeleted(item)) 
     filteredItems.Add(item); 
}