सवाल Iterator बनाम के लिए


मुझे एक साक्षात्कार में पूछा गया था कि लूप के लिए इटरेटर का उपयोग करने का क्या फायदा है या इटरेटर पर लूप के लिए उपयोग करने का क्या फायदा है?

क्या कोई भी शरीर इसका उत्तर दे सकता है ताकि भविष्य में यदि मुझे समान प्रश्न का सामना करना पड़े तो मैं इसका जवाब दे सकता हूं


44
2018-03-08 10:09


मूल


एक के लिए प्रत्येक लूप कवर के तहत एक इटरेटर का उपयोग करता है। अंतर केवल पठनीयता (और इसलिए रखरखाव) है। - Dawood ibn Kareem
कुंआ; आपने क्यों कहा Iterator? - Boris the Spider
आपको तुरंत जवाब देने के लिए कुछ भी नहीं है। आप अलग-अलग प्रकार के संग्रहों के बारे में तर्क दे सकते हैं, दृश्य के पीछे प्रत्येक कोड क्या करता है, और कारणों की आपकी क्षमता दिखाता है, भले ही आप एक निश्चित उत्तर नहीं बना सकते। यही महत्वपूर्ण है: सोचने में सक्षम होना। मैं इसके साथ अपना जवाब शुरू करूंगा: "ठीक है, मुझे नहीं पता। मुझे लगता है कि यह इस बात पर निर्भर करता है कि आप क्या करना चाहते हैं, और किस तरह का संग्रह है। दोनों का उपयोग करने का एक अच्छा कारण होना चाहिए, लेकिन यह निर्भर होना चाहिए स्थिति। आइए कल्पना करें कि एक ऐरेलिस्ट के साथ क्या होता है। फिर एक लिंक्डलिस्ट आदि के साथ। " - JB Nizet
मैं पूरी तरह से @JBNizet से सहमत हूं। कह रहा है कि मुझे यादृच्छिक विकल्प चुनने से ज्यादा बेहतर नहीं पता - यह मुझे इंप्रेशन देता है कि प्रोग्रामिंग के दौरान आप ऐसा करेंगे; सोचने के बिना दिमाग में आने वाली पहली चीज़ चुनें। आप क्षेत्र में अपने ज्ञान को आजमा सकते हैं और बता सकते हैं कि आप एक सूचित उत्तर देने के लिए पर्याप्त नहीं जानते हैं। - Boris the Spider
दोनों मौजूदा उत्तर अपूर्ण हैं। सबसे पहले, 2 प्रकार के लूप हैं, जो बहुत अलग तरीके से व्यवहार करते हैं। एक सूचकांक का उपयोग करता है (जो हमेशा संभव नहीं होता है), और दूसरा दृश्यों के पीछे एक इटरेटर का उपयोग करता है। तो वास्तव में आप तुलना करने के लिए 3 loops है। फिर आप उन्हें विभिन्न शर्तों में तुलना कर सकते हैं: प्रदर्शन, पठनीयता, त्रुटि-विशिष्टता, क्षमता। एक इटरेटर चीजें कर सकता है कि एक foreach पाश नहीं कर सकते हैं। लेकिन एक इटरेटर अधिक खतरनाक और कम पठनीय है। और तत्वों तक पहुंचने के लिए सूचकांक का उपयोग केवल सूचियों के साथ करने योग्य है, लेकिन यदि यह एक लिंक की गई सूची है तो यह प्रभावी नहीं है। तो कोई "सर्वश्रेष्ठ" तरीका नहीं है। - JB Nizet


जवाब:


सबसे पहले, 2 प्रकार के लूप हैं, जो बहुत अलग तरीके से व्यवहार करते हैं। एक सूचकांक का उपयोग करता है:

for (int i = 0; i < list.size(); i++) {
    Thing t = list.get(i);
    ...
}

इस प्रकार का पाश हमेशा संभव नहीं होता है। उदाहरण के लिए, सूचियों में सूचकांक होते हैं, लेकिन सेट नहीं करते हैं, क्योंकि वे अनियंत्रित संग्रह होते हैं।

दूसरा, फोरैच लूप दृश्यों के पीछे एक इटरेटर का उपयोग करता है:

for (Thing thing : list) {
    ...
}

यह हर प्रकार के इटेरेबल संग्रह (या सरणी) के साथ काम करता है

और अंत में, आप एक इटरेटर का उपयोग कर सकते हैं, जो किसी भी इटेबल के साथ भी काम करता है:

for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
    Thing t = it.next();
    ...
} 

तो वास्तव में आप तुलना करने के लिए 3 loops है।

आप उन्हें विभिन्न शर्तों में तुलना कर सकते हैं: प्रदर्शन, पठनीयता, त्रुटि-विशिष्टता, क्षमता।

एक इटरेटर चीजें कर सकता है कि एक foreach पाश नहीं कर सकते हैं। उदाहरण के लिए, यदि आप पुनरावृत्त करते समय तत्वों को हटा सकते हैं, यदि इटरेटर इसका समर्थन करता है:

for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
    Thing t = it.next();
    if (shouldBeDeleted(thing) {
        it.remove();
    }
} 

सूचियां इटरेटर भी प्रदान करती हैं जो दोनों दिशाओं में पुनरावृत्त हो सकती हैं। एक फोरैच लूप केवल शुरुआत से अंत तक चलता है।

लेकिन एक इटरेटर अधिक खतरनाक और कम पठनीय है। जब एक फोरैच पाश आपको चाहिए, तो यह सबसे पठनीय समाधान है। एक पुनरावर्तक के साथ, आप निम्न कार्य कर सकते हैं, जो एक बग होगा:

for (Iterator<Thing> it = list.iterator(); it.hasNext(); ) {
    System.out.println(it.next().getFoo());
    System.out.println(it.next().getBar());
} 

एक फोरच लूप ऐसी बग होने की अनुमति नहीं देता है।

तत्वों तक पहुंचने के लिए सूचकांक का उपयोग करना सरणी द्वारा समर्थित संग्रहों के साथ थोड़ा अधिक कुशल है। लेकिन अगर आप अपने दिमाग को बदलते हैं और एक ऐरेलिस्ट के बजाय लिंक्डलिस्ट का उपयोग करते हैं, तो अचानक प्रदर्शन भयानक होगा, क्योंकि प्रत्येक बार जब आप पहुंचते हैं list.get(i), लिंक्ड सूची को लूप करना होगा हालांकि इसके सभी तत्व ith एक तक होंगे। एक इटरेटर (और इस प्रकार फोरैच लूप) में यह समस्या नहीं है। यह हमेशा दिए गए संग्रह के तत्वों के माध्यम से पुन: प्रयास करने का सबसे अच्छा तरीका उपयोग करता है, क्योंकि संग्रह में स्वयं का इटरेटर कार्यान्वयन होता है।

अंगूठे का मेरा सामान्य नियम है: फोरैच लूप का उपयोग करें, जब तक कि आपको वास्तव में एक इटरेटर की क्षमताओं की आवश्यकता न हो। मैं केवल ऐरे के साथ सूचकांक के साथ लूप के लिए उपयोग करता हूं, जब मुझे लूप के अंदर इंडेक्स तक पहुंच की आवश्यकता होती है।


81
2018-03-08 10:47



जब आप किसी संग्रह में एक या अधिक तत्वों को निकालने के लिए इटरेटर का उपयोग करते हैं, तो यह करना सुरक्षित है। जब आप प्रत्येक के लिए या लूप के लिए उपयोग करते हैं, तो निकालने की अनुमति नहीं है या किसी बग का कारण बनता है क्योंकि संग्रह पर लूपिंग करते समय हटाते समय संग्रह में प्रत्येक तत्व की अनुक्रमणिका बदल जाती है। इसलिए आपको लूप के लिए रिवर्स का उपयोग करना चाहिए, या बग को शुरू करने से रोकने के लिए एक इटरेटर का उपयोग करना चाहिए। यह भी देखें उत्तर। - user504342
"ith" आपने कहा, अंग्रेजी भाषा में एक चुनौती है। - M D P


इटरेटर लाभ:

  • संग्रह से तत्वों को हटाने की क्षमता।
  • आगे और पीछे जाने के लिए आगे बढ़ने की क्षमता next() तथा previous()
  • जांचने की क्षमता है कि क्या अधिक तत्व हैं या नहीं hasNext()

लूप को केवल एक से अधिक करने के लिए डिज़ाइन किया गया था Collection, तो अगर आप सिर्फ एक पर फिर से शुरू करना चाहते हैं Collection, जैसे लूप का उपयोग करना बेहतर है for-Each, लेकिन यदि आप और अधिक चाहते हैं कि आप इटरेटर का उपयोग कर सकें।


13
2018-03-08 10:15



और एक के साथ ListIterator आप भी कर सकते हैं add और एक मनमाना बिंदु पर पुनरावृत्ति शुरू करें। - Boris the Spider


यदि आप संख्या से डेटा तक पहुंचते हैं (उदा। "i"), तो जब आप सरणी का उपयोग करते हैं तो यह तेज़ होता है। क्योंकि यह सीधे तत्व के लिए जाता है

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

यदि आप इटरेटर का उपयोग करते हैं, तो संकलक जानता है कि आप कहां हैं। तो इसे ओ (1) की जरूरत है (क्योंकि, यह वर्तमान स्थिति से शुरू होता है)

अंत में, यदि आप केवल सरणी या डेटा संरचना का उपयोग करते हैं जो प्रत्यक्ष पहुंच का समर्थन करता है (उदाहरण के लिए जावा पर सरणीसूची)। "एक [i]" अच्छा है। लेकिन, जब आप अन्य डेटा संरचना का उपयोग करते हैं, तो इटरेटर अधिक कुशल होता है


10
2018-03-08 10:17



तो मुझे कहना चाहिए कि यह आवश्यकता पर निर्भर करता है। - rocking
जावा पर इंडेक्स द्वारा लूप का उपयोग करने के नुकसान को इंगित करने के लिए +1 Collections। यह इंगित करने लायक है कि लूप के लिए एक उन्नत एक का उपयोग करता है Iterator हुड के नीचे। - Boris the Spider
आपके अन्य डेटा संरचना उदाहरण उपयोगी नहीं हैं - एक ArrayList अनुक्रमित पहुंच प्रदान करता है। शायद विशिष्ट जावा संग्रह शामिल करने के लिए अद्यतन? (उदाहरण के लिए ArrayList बनाम लिंक्डलिस्ट) - Richard Miskin


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

जब आपका कोड इस फॉर्म में या तो इटरेटर का उपयोग करता है

for(Item element : myCollection) { ... }

यह रूप

Iterator<Item> iterator = myCollection.iterator();
while(iterator.hasNext()) {    
    Item element = iterator.next();    
    ... 
}

या यह रूप

for(Iterator iterator = myCollection.iterator(); iterator.hasNext(); ) {
   Item element = iterator.next();
   ...
}

आपका कोड क्या कह रहा है "मुझे संग्रह के प्रकार और इसके कार्यान्वयन की परवाह नहीं है, मुझे बस परवाह है कि मैं इसके तत्वों के माध्यम से पुन: प्रयास कर सकता हूं"। जो आमतौर पर बेहतर दृष्टिकोण होता है, क्योंकि यह आपके कोड को अधिक decoupled बनाता है।

दूसरी तरफ, यदि आप लूप के लिए क्लासिक का उपयोग कर रहे हैं, जैसा कि अंदर है

for(int i = 0; i < myCollection.size(); i++) {
   Item element = myCollection.get(i);
   ...
}

आपका कोड कह रहा है, मुझे संग्रह के प्रकार को जानने की जरूरत है, क्योंकि मुझे अपने तत्वों के माध्यम से एक विशिष्ट तरीके से पुन: प्रयास करने की आवश्यकता है, मैं संभवतः नल के लिए जांच करने जा रहा हूं या पुनरावृत्ति के क्रम के आधार पर कुछ परिणाम गणना कर रहा हूं। जो आपके कोड को अधिक नाजुक बनाता है, क्योंकि यदि किसी भी समय आपके द्वारा प्राप्त किए गए संग्रह के प्रकार में परिवर्तन होता है, तो यह आपके कोड के तरीके को प्रभावित करेगा।

इसे सारांशित करना, अंतर, या स्मृति उपयोग के बारे में इतना अंतर नहीं है, आपके कोड को डीकॉप्लिंग करने के बारे में अधिक है ताकि परिवर्तन से निपटने के लिए अधिक लचीला हो।


6
2018-03-08 12:28