2012-07-25 33 views
12

सी # में, IEnumerator इंटरफ़ेस एक संग्रह पार और तत्वों को देखने के लिए एक तरह से परिभाषित करता है। मुझे लगता है कि यह बहुत उपयोगी है क्योंकि यदि आप किसी विधि में IEnumerable<T> पास करते हैं, तो यह मूल स्रोत को संशोधित नहीं करेगा।इटरेटर हटाने() ऑपरेशन को परिभाषित क्यों करता है?

हालांकि, जावा में, Iteratorremove ऑपरेशन को परिभाषित करता है (वैकल्पिक रूप से!) तत्वों को हटाने की अनुमति देता है। Iterable<T> को किसी विधि में पास करने में कोई फायदा नहीं है क्योंकि वह विधि मूल संग्रह को अभी भी संशोधित कर सकती है।

remove के optionalnessrefused bequest गंध का एक उदाहरण है, लेकिन अनदेखी कि (पहले से ही here चर्चा की) मैं डिजाइन फैसले कि एक remove घटना के लिए प्रेरित किया इंटरफेस पर लागू किया जाना में रुचि होगी।

क्या डिजाइन फैसले कि remove करने के लिए नेतृत्व Iterator को जोड़ा जा रहा है?

एक और तरीका रखने के लिए, सी # डिज़ाइन निर्णय क्या है जो स्पष्ट रूप से remove पर IEnumerator पर परिभाषित नहीं है?

उत्तर

8

Iterator यात्रा के दौरान तत्वों को दूर करने में सक्षम है। आप इटरेटर का उपयोग करके संग्रह को पुन: सक्रिय नहीं कर सकते हैं और उस संग्रह की remove() विधि का उपयोग करके लक्ष्य संग्रह से तत्वों को हटा सकते हैं। Iterator.next() के अगले कॉल पर आपको ConcurrentModificationException मिलेगा क्योंकि इटरेटर यह नहीं जान सकता कि संग्रह वास्तव में कैसे बदला गया था और यह नहीं पता कि पुनरावृत्ति कैसे जारी रखना है।

जब आप iterator यह जानता है कि कैसे संग्रह बदल गया था की remove() उपयोग कर रहे हैं। इसके अलावा वास्तव में आप संग्रह के किसी तत्व को नहीं हटा सकते हैं, बल्कि केवल वर्तमान ही। यह पुनरावृत्ति की निरंतरता को सरल बनाता है।

इटरेटर या इटेबल योग्य होने के फायदों के बारे में: आप हमेशा अपने संग्रह में संशोधन को रोकने के लिए Collection.unmodifireableSet() या Collection.unmodifireableList() का उपयोग कर सकते हैं।

+0

'unmodifiableXYZ' हालांकि एक रनटाइम चीज़ है, मुझे स्थिर इनविएंट पसंद हैं। मुझे डिज़ाइन के फैसले में अधिक दिलचस्पी थी जिसके कारण 'हटाया जा रहा' और शायद सी # ने भी क्यों नहीं चुना। –

+0

'unmodifiableXYZ' का उपयोग करने के लिए बुरी चीज यह है कि अगर किसी ने पहले से ही लिपटा हुआ 'XYZ' पारित किया है, तो आप इसे दो बार लपेट सकते हैं, और जब तक आप इसे काम करने के लिए प्रतिबिंब का उपयोग नहीं करते हैं तब तक आपके पास इससे बचने का कोई तरीका नहीं है। हालांकि मुझे विश्वास है कि कार्यान्वयन इसे अनुकूलित करेगा, यह अभी भी मेरे लिए बहुत बुरा लग रहा है। –

+0

ओपनजेडीके कार्यान्वयन को देखते हुए, यह किसी भी एकाधिक रैपिंग से बचने के लिए प्रतीत नहीं होता है। इसका मतलब है कि एक जटिल अनुप्रयोग में आप आखिरकार 100 बार या उससे अधिक के लिए एक सरल 'ऐरेलिस्ट ' लपेट सकते हैं। –

1

स्थितियों में, जहां आप इटरेटर का उपयोग कर, क्योंकि यह यह करने के लिए सबसे कारगर तरीका है तत्वों को दूर करने में सक्षम होना चाहते हैं। उदाहरण के लिए, जब किसी लिंक किए गए डेटा संरचना (जैसे एक लिंक्ड सूची) traversing, इटरेटर का उपयोग कर निकालते समय एक O(1) आपरेशन है ... List.remove() संचालन के माध्यम से O(N) की तुलना में।

और बेशक, कई संग्रह तैयार कर रहे हैं ताकि Iterator.remove() से किसी अन्य माध्यम से एक संग्रह के दौरान संग्रह को संशोधित करने के लिए एक ConcurrentModificationException का परिणाम देगा।


आप एक स्थिति है जहाँ आप एक संग्रह iterator के माध्यम से संशोधन की अनुमति देने के लिए, यह Collection.unmodifiableXxxx उपयोग करने और इसे इटरेटर है वांछित प्रभाव होगा का उपयोग कर लपेटकर नहीं करना चाहती है। वैकल्पिक रूप से, मुझे लगता है कि अपाचे कॉमन्स एक साधारण अपरिवर्तनीय इटरेटर रैपर प्रदान करता है।


तरह से एक ही "गंध" Iterator रूप से IEnumerable ग्रस्त हैं। reset() विधि पर एक नज़र डालें। मैं भी उत्सुक था कि सी # LinkedList वर्ग O(N) समस्या से निपटने के तरीके से कैसे निपटता है। ऐसा लगता है कि यह द्वारा सूची के आंतरिक भाग को उजागर करता है ...First और Last गुणों के रूप में जिनके मूल्य LinkedListNode संदर्भ हैं। यह एक और डिजाइन सिद्धांत का उल्लंघन करता है ... और (आईएमओ) Iterator.remove() से कहीं अधिक खतरनाक है।

+0

मुझे एहसास है कि 'रीसेट' एक ही गंध है, लेकिन (जैसा कि मैंने सवाल में राज्य करने की कोशिश की), मुझे इसमें वास्तव में दिलचस्पी नहीं है। 'रीसेट' किसी को भी कंटेनर की सामग्री को हटाने की अनुमति नहीं देता है। विवाद का मेरा मुख्य बिंदु यह है कि सी # की पुनरावृत्ति संग्रह को उसी तरह से छोड़ देगी, इससे कोई फर्क नहीं पड़ता कि इसके साथ क्या तरीका है (प्रतिबिंब को अनदेखा करना)। –

+0

@ जेफफोस्टर - जैसा कि मैंने कहा था, जावा इटरेटर्स गारंटी प्रदान नहीं करते हैं ... लेकिन यदि आप इसे चाहते हैं, तो इसे प्राप्त करने के लिए सरल और सस्ती तरीके हैं। –

+0

yup, मैं सिर्फ यह जानना चाहता हूं कि वे गारंटी क्यों प्रदान नहीं करते हैं। 'निकालें' का समर्थन करने (या समर्थन नहीं) करने के लिए जावा/सी # लाइब्रेरी डिज़ाइन स्तर पर समझौते के किस सेट ने किया था। –

2

शायद यह इस तथ्य के कारण है कि संग्रह पर वस्तुओं को हटाने के दौरान हमेशा बग और अजीब व्यवहार का कारण रहा है। प्रलेखन पढ़ने से यह सुझाव देगा कि रनटाइम निकालने पर जावा लागू होता है() को केवल कॉल पर एक बार कॉल किया जाता है() जो मुझे लगता है कि इसे अभी भी जोड़ दिया गया है ताकि लोगों को सूची में डेटा को हटाने से रोकने के लिए जोड़ा जा सके।

-1

यह वास्तव में जावा की एक शानदार विशेषता है। जैसा कि आप अच्छी तरह से जानते हैं, जब तत्वों को हटाने के लिए .NET में किसी सूची के माध्यम से पुनरावृत्ति करते हैं (जिनमें से कई उपयोग के मामले हैं) तो आपके पास केवल दो विकल्प हैं।

var listToRemove = new List<T>(originalList); 
foreach (var item in originalList) 
{ 
    ... 
    if (...) 
    { 
     listToRemove.Add(item) 
    } 
    ... 
} 

foreach (var item in listToRemove) 
{ 
    originalList.Remove(item); 
} 

या

var iterationList = new List<T>(originalList); 
for (int i = 0; i < iterationList.Count; i++) 
{ 
    ... 
    if (...) 
    { 
     originalList.RemoveAt(i); 
    } 
    ... 
} 

अब, मैं दूसरे को पसंद करते हैं, लेकिन जब मैं एक आइटम पर कर रहा हूँ मैं इसे हटाने और अभी तक कर सकते हैं क्योंकि जावा के साथ मैं यह सब की जरूरत नहीं है पुनरावृत्ति जारी रहेगा! ईमानदारी से, हालांकि यह जगह से बाहर प्रतीत हो सकता है, यह वास्तव में कई तरीकों से एक अनुकूलन है।

+0

इसके विपरीत, मैं इसे घृणित के रूप में देखता हूं। यह मुझे बिना किसी तरीके से तत्वों का एक सेट पारित करने में सक्षम होने के बिना रोकता है कि विधि मेरे कंटेनर को टोस्ट करेगी :) मुझे डिजाइन निर्णय में दिलचस्पी है जिसके कारण इसे जोड़ा जा रहा है, और विशेष रूप से यह सी # में क्यों नहीं है। –

+0

इसे अपने कंटेनर को टोस्ट करने के लिए @ स्टीफनसी की पोस्ट का पालन करें - लेकिन मुझे लगता है कि आप इस सवाल को गलत जगह पर पूछ रहे हैं यदि आप यह पता लगाने की कोशिश कर रहे हैं कि जावा डिज़ाइनर ने इसे क्यों लागू किया और माइक्रोसॉफ्ट ने क्यों नहीं किया। पता है क्या मेरा मतलब है? लेकिन उपर्युक्त पर विचार करें और इस बारे में सोचें कि यह कितना अधिक कुशल है। साथ ही, क्या यह एक तरीका है जिसे आप नियंत्रित करते हैं या यह एक ढांचे से है जिसे आप खा रहे हैं? –

+0

आपका उदाहरण पूरी तरह से गलत है।सी # और जावा दोनों 'सूची ' के लिए 'RemoveAt' विधि प्रदान करते हैं। तो कोड की आपकी जावा शैली सी # के लिए भी काम करती है। यदि आपका सी # कोड 'foreach' संरचना का उपयोग करता है तो आपको जावा में' :) (:) 'का उपयोग करना चाहिए। और आप देखेंगे कि आप वास्तव में ऐसे लूप में 'निकालें' विधि को कॉल नहीं कर सकते हैं (क्योंकि आपके पास 'Iterator' का स्पष्ट संदर्भ नहीं है), इसलिए जावा का आपका "लाभ" चला गया। –