2012-02-05 13 views
5

मैं बहुतसी # संकेत दिए गए, iterators और जेनरिक

स्टम्प्ड हूँ मैं एक सी ++ इटरेटर की तरह सी # में एक iterator उपयोग कर सकते हैं कैसे? मुझे एक शुरुआत() या अंत() एक्सेसर नहीं मिल रहा है, मैं यह भी नहीं पता कि एक इटरेटर घोषित कैसे किया जाए। मैंने Ienumerator के बारे में पढ़ा है। मेरा लक्ष्य मर्ज फ़ंक्शन को कार्यान्वित करना है। यहां C++ में लिखे गए मेरे मर्ज फ़ंक्शन का हिस्सा है। अधिकांशतः, मैं दिखाए गए सी # समकक्ष की तलाश में हूं, सिवाय इसके कि मैं पूर्णांक के बजाय संदर्भ प्रकार का उपयोग करूँगा।

void merge(vector<int>::iterator left, vector<int>::iterator right, vector<int>::iterator  leftEnd, vector<int>::iterator rightEnd, vector<int>::iterator full) 
{ 

    while(left != leftEnd && right!= rightEnd) //compare left and right until the end of the vector is reached 
    { 
     if(*right < *left)  //right < left so insert right to the output vector and advance the iterators 
     { 
      *full++ = *right++; 
     } 
     else     //left < right so insert left to the output vector and advance the iterators 
     { 
      *full++ = *left++; 
     } 
    } 

    while(left != leftEnd) //copy any remaining elements into the output from left 
    { 
     *full++ = *left++; 
    } 
} 

इसके अलावा, मुझे किस संग्रह का उपयोग करना चाहिए? (वर्तमान में मैं List<T> और LinkedList<T>) का प्रयास कर रहा हूं। - नेट iterators आप अंतर्निहित संग्रह में परिवर्तन कर न दें

bool leftValid = left.MoveNext(); 
bool rightValid = right.MoveNext(); 

while (leftValid && rightValid) 
{ 
    if (right.Current < left.Current) 
    { 
     full.Add(right.Current); 
     rightValid = right.MoveNext(); 
    } 
    else 
    { 
     full.Add(left.Current); 
     leftValid = left.MoveNext(); 
    } 
} 

while (leftValid) 
{ 
    full.Add(left.Current); 
    leftValid = left.MoveNext();  
} 

while (rightValid) 
{ 
    full.Add(right.Current); 
    rightValid = right.MoveNext();  
} 

यहाँ fullIList<T> किसी प्रकार की आवश्यकता होगी:

+0

क्या आप [Enumerable.Concat (TSource) विधि को फिर से कार्यान्वित नहीं कर रहे हैं] (http://msdn.microsoft.com/en-us/library/bb302894.aspx)? –

+0

@ सर्ज संख्या, यह मर्ज सॉर्ट का मर्ज हिस्सा है। नोट 'अगर (* दाएं <* बाएं)' – CodesInChaos

उत्तर

7

ऐसा लगता है कि आप की तरह कुछ चाहता हूँ लगता है।

आपको "ब्रिजिंग" कोड लिखने का प्रयास नहीं करना चाहिए ताकि आप सीई ++ वाले .NET iterators का उपयोग कर सकें; जब आप .NET का उपयोग कर रहे हों तो .NET iterators के संदर्भ में सोचना शुरू करना बेहतर होगा।

ध्यान दें कि .NET में आसपास के इटरेटर को पास करना बहुत दुर्लभ है। यह अधिक IEnumerable<T> मानकों करने के लिए अपने विधि बनाने के लिए प्राकृतिक हो, और की तरह कुछ करना होगा:

using (IEnumerable<T> leftIterator = leftSequence.GetEnumerator()) 
{ 
    using (IEnumerable<T> rightIterator = rightSequence.GetEnumerator()) 
    { 
     // Code as above, just using leftIterator and rightIterator 
     // instead of left and right 
    } 
} 
+1

और ध्यान दें कि 'पूर्ण' एक पुनरावर्तक नहीं हो सकता है क्योंकि .NET एन्युमेटर केवल पढ़ने के लिए हैं। आपको इसके बजाए 'IList' जैसे कुछ में गुजरना होगा। –

+0

@MattiVirkkunen: वास्तव में - यह ध्यान देगा। –

+0

@CodeInChaos: क्षमा करें, हाँ, मैं अपरिवर्तनीयता के बारे में थोड़ा सा स्पष्टीकरण दूंगा। मुझे यकीन नहीं है कि .NET के बारे में आपका मतलब क्या है, यह पुनरावृत्तियों की प्रतियां बनाने में सहायता नहीं करता है - आप एक विधि बना सकते हैं जो दो 'आईएन्यूमेरेटर है और यह ठीक काम करेगा। यह 'आईन्यूमेरेबल ' लेने के लिए और अधिक समझ में आएगा, आपको दिमाग में। मैं इसके लिए संपादित करूंगा। –

2

मुझे लगता है कि आप चाहते हैं GetEnumerator(), MoveNext(), और वर्तमान।

आम तौर पर, आप केवल पुनरावृत्ति के लिए foreach का उपयोग कर सकते हैं, लेकिन आपका मामला विशेष है।

यदि तथ्य "पूर्ण" का उपयोग करने के बजाय, इसे एक पुनरावर्तक ब्लॉक के रूप में व्यवस्थित करें और दो संख्याओं को आलसी ढंग से मर्ज करें।

IEnumerable<T> Merge<T>(IEnumerable<T> left, IEnumerable<T> right) 
{ 
    ... yield return Min<T>(left.Current, right.Current); .., 
} 
3

.नेट कंटेनर सी ++ स्टाइल इटरेटर्स का समर्थन नहीं करते हैं। केवल एक चीज है वे एक

  • सरल आगे इटरेटर IEnumerator<T>
  • जो संग्रह
  • संशोधित नहीं कर सकते कहा जाता है रैंडम एक्सेस
  • कॉपी नहीं किया जा सकता है नहीं है (कुछ संग्रह मान प्रकार है iterators कॉपी किया जा सकता है जो, लेकिन यह मुश्किल व्यापार और शायद ही कभी इस्तेमाल) है
  • और सबसे संग्रह भी अवैध हो जाता है जब भी आप संग्रह को संशोधित पर

बहुत कुछ एकमात्र चीज जो वे कर सकते हैं उसे foreach कथन में फिर से चालू किया जा रहा है।


आप जो रैंडम एक्सेस की अनुमति देता है, लेकिन केवल संग्रह जो तेजी से अनुक्रमण समर्थन पर समर्थित है IList<T> इंटरफेस में देखना चाहते हो सकता है। ऐसे संग्रह पर आप इंडेक्स का उपयोग कर इन-प्लेस मर्ज सॉर्ट को कार्यान्वित कर सकते हैं।

void Merge<T>(IList<T> container,int left, int right, int leftEnd, int rightEnd, int full) 

और फिर container[left] बजाय *left का उपयोग करें।


इस की दुर्भाग्यपूर्ण परिणाम यह है कि आप एक कुशल यथा-स्थान कंटेनर नास्तिक छँटाई समारोह लागू नहीं कर सकते जैसे सी ++ है, है।

+0

यदि हम इटरेटर को एक सुविधाजनक कंटेनर अज्ञेयवादी हैंडल के रूप में परिभाषित करते हैं जो वर्तमान स्थिति को बनाए रखता है और नेविगेशन को सक्षम करता है, तो केवल इटेटरेटर प्रकार .NET समर्थन आगे पढ़ने वाला इटरेटर है। जो दयालु है। कई नॉनट्रिविअल एल्गोरिदम में बिडरेक्शनल या यादृच्छिक एक्सेस इटरेटर्स के लिए बहुत सारे उपयोग हैं। –

0

आप सरणी का उपयोग कर सकते हैं, जिसमें एक निश्चित आकार है, या List<T>, जिसे अन्य भाषाओं में ArrayLists भी कहा जाता है। उनके आइटम को इंडेक्सर (list[i]) के माध्यम से एक्सेस किया जा सकता है और आइटम list.Add(item); के साथ जोड़ा जा सकता है। वे स्वचालित रूप से बढ़ते हैं। LinkedLists को एक इंडेक्सर के माध्यम से एक्सेस नहीं किया जा सकता है और इसे पार किया जाना चाहिए।

आप इस

void merge(IEnumerator<int> left, IEnumerator<int> right, 
      List<int> full) 
{ 
    // Jon Skeet's code goes here 
} 

की तरह विधि घोषणा करेंगे आप इस

IEnumerable<int> intEnumerable = ...; 
IEnumerator<int> intEnumerator = intEnumerable.GetEnumerator(); 

IEnumerable<T> की तरह एक प्रगणक प्राप्त कर सकते हैं सबसे सामान्य संग्रह प्रकार से कार्यान्वित किया जाता है। गैर सामान्य संग्रह आमतौर पर IEnumerable लागू करते हैं।

(@ CodeInChaos की टिप्पणी के जवाब में संपादित)।

+0

कोई गणना नहीं है जिसे आप 'बाएं'/'दाएं 'पास कर सकते हैं। वे आंशिक रूप से पुनरावृत्त इटरेटर्स की प्रतियां हैं। – CodesInChaos

+0

मुझे नहीं लगता कि आपका संपादन समस्या को संबोधित करता है। वे इटरेटर संभवतः एक ही कंटेनर में विभिन्न तत्वों को इंगित करते हैं। उन्हें सूची में सूचकांक के रूप में सोचें, लेकिन उन संग्रहों पर काम करना जो तेजी से अनुक्रमण का समर्थन नहीं करते हैं। – CodesInChaos

+0

एक 'आईन्यूमेरेटर ' ('IENumerable '!) ** ** एक सूची में ** एक प्रकार का सूचकांक है। 'बाएं 'और' दाएं 'अब एक ही संग्रह में अलग-अलग स्थानों पर इंगित कर सकते हैं। (मैंने अपने प्रकार को 'IENumerable ' से 'IENumerator ') –

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