2010-05-07 14 views
13

मेरे पास तारों के दो संग्रह हैं: CollectionA सिस्टम में संग्रहीत ऑब्जेक्ट की एक स्ट्रिंगकोलेक्शन प्रॉपर्टी है, जबकि संग्रह बी रनटाइम पर जेनरेट की गई सूची है। यदि कोई अंतर है तो संग्रह बी से मिलान करने के लिए संग्रह ए को अद्यतन करने की आवश्यकता है। तो मैंने हटाने की कोशिश की कि मुझे हटाने के लिए एक सरल LINQ विधि होने की उम्मीद है।मुझे एकत्रित संग्रह को संशोधित नहीं करते समय "संग्रह संशोधित किया गया था; गणना ऑपरेशन निष्पादित नहीं हो सकता है"?

var strDifferences = CollectionA.Where(foo => !CollectionB.Contains(foo)); 
foreach (var strVar in strDifferences) { CollectionA.Remove(strVar); } 

लेकिन मैं strDifferences पर एक "Collection was modified; enumeration operation may not execute" त्रुटि हो रही है ... भले ही यह संग्रह संशोधित किया जा रहा से एक अलग गणनीय है! मैंने मूल रूप से इस त्रुटि को बचने के लिए स्पष्ट रूप से तैयार किया है, क्योंकि मेरा पहला कार्यान्वयन इसे उत्पन्न करेगा (जैसा कि मैं CollectionA पर अनुमान लगा रहा था और !CollectionB.Contains(str) पर हटा रहा था)। क्या कोई इस बारे में कुछ अंतर्दृष्टि निकाल सकता है कि यह गणना क्यों विफल रही है?

उत्तर

21

दोनों पूरी तरह से अलग नहीं हैं। Where संग्रह की एक अलग प्रति नहीं बनाता है। यह मूल रूप से मूल संग्रह का संदर्भ रखता है और आपसे अनुरोध करते समय तत्वों को प्राप्त करता है।

ToList() को Where को तुरंत संग्रह के माध्यम से लागू करने के लिए आप अपनी समस्या का समाधान कर सकते हैं।

var strDifferences = CollectionA 
    .Where(foo => !CollectionB.Contains(foo)) 
    .ToList(); 
+0

'ToArray() 'बेहतर नहीं होगा? 'सूची' का उपयोग करने की कोई आवश्यकता नहीं है। – svick

+0

@svick यह कुछ ऐसा है जो मैंने कुछ समय के लिए सोचा है, लेकिन यह एक प्रश्न होगा जो मैं किसी अन्य दिन पूछूंगा। बशर्ते कि यह पहले से ही नहीं पूछा गया है, बकल- –

+1

@ ग्रेस नोट को यहां पकड़ें: http://stackoverflow.com/questions/1105990/is-it-better-to-call-tolist-or-toarray-in -linq-query – nawfal

3

Where वापस IEnumerable<T> गुजरता है और फिर आपको लगता है कि प्रयोग कर रहे हैं अपने foreach (var strVar in strDifferences)

में तो आप संग्रह है कि IEnumerable<T> बनाया से निकालने के लिए कोशिश कर रहे हैं। आपने कोई नई सूची नहीं बनाई है, यह अगले आइटम को खींचने के लिए CollectionA का संदर्भ दे रहा है, ताकि आप CollectionA संपादित नहीं कर सकें। जब से तुम जो कि CollectionB में नहीं हैं हटा रहे हैं

var strDifferences = CollectionA.Where 
    (foo => CollectionB.Contains(foo)).ToList(); 

CollectionA = strDifferences; 
//or instead of reassigning CollectionA 
CollectionA.Clear(); 
CollectionA.AddRange(strDifferences); 

:

आप यह भी कर सकते हैं। बस उन लोगों की तलाश करें, एक सूची बनाएं और संग्रह सूची को उस सूची को असाइन करें।

+0

आह ... मुझे आपके विकल्प का उपयोग करना अच्छा लगेगा (हालांकि यह वास्तव में समान है), लेकिन दुर्भाग्य से संग्रह ए, यह पता चला है, केवल पढ़ने योग्य संपत्ति है, इसलिए मैं इसे सेट नहीं कर सकता। आप बहुत अधिक गहराई से स्पष्टीकरण देते हैं, हालांकि, इसके लिए +1। –

+0

@ccornet अगर इसे सेट नहीं किया जा सकता है तो आप इसे साफ़ कर सकते हैं और आइटम को वापस जोड़ सकते हैं। – kemiller2002

+0

मैंने इसके बारे में लंबे और कठिन विचार किया। मैंने अभी भी हटाने के दृष्टिकोण के साथ जाने का फैसला किया। मैं संग्रह ए को संशोधित नहीं करना चाहता हूं यदि कोई बदलाव आवश्यक नहीं है, तो हटाए जाने की जरूरतों की एक सूची बनाने से यह बहुत तेज़ और सरल हो जाता है (केवल देखें कि strDifferences.Count> 0)। यदि मैं लक्ष्य की एक सरणी बनाता हूं, तो मुझे अभी भी जांचना होगा कि क्या संग्रह ए में कुछ ऐसा है जिसे हटाया जाना चाहिए। –

3

पहली पंक्ति थोड़ा संशोधित करने का प्रयास:

var strDifferences = 
    CollectionA.Where(foo => !CollectionB.Contains(foo)).ToList(); 

मुझे लगता है कि LINQ आपकी क्वेरी के आलसी निष्पादन उपयोग कर रहा है। ToList पर कॉल करने से पहले क्वेरी के निष्पादन को मजबूर कर दिया जाएगा।

+0

हां, और सुनिश्चित करें कि इसे दो पंक्तियों में न डालें I..e। var strDifferencesTemp = संग्रह ए। जहां (foo =>! CollectionB.Contains (foo)); var strDifferences = strDifferencesTemp.ToList(); यदि आप ऐसा करते हैं, तो संग्रह को इन दो पंक्तियों के बीच किसी अन्य धागे द्वारा संशोधित किया जा सकता है। – Markus

संबंधित मुद्दे

 संबंधित मुद्दे