2012-05-24 15 views
11

मैं एक IEnumerable<T> है के लिए अलग अलग है। मैं पिछले आइटम है, जो करने के लिए मैं कुछ और करना चाहते हैं को छोड़कर, संग्रह की प्रत्येक आइटम के लिए एक बात करना चाहते हैं। मैं इसे अच्छी तरह से कैसे कोड कर सकता हूं? स्यूडोकोडIEnumerable foreach, कुछ पिछले तत्व

foreach (var item in collection) 
{ 
    if (final) 
    { 
     g(item) 
    } 
    else 
    { 
     f(item) 
    } 
} 

में तो अगर मेरे IEnumerable Enumerable.Range(1,4) थे मैं च कर चाहते हैं (1) च (2) च (3) जी (4)। एनबी। यदि मेरा आईनेमरेबल लंबाई 1 होता है, तो मुझे जी (1) चाहिए।

मेरे IEnumerable Count() पूरी बात से अधिक पाशन के रूप में के रूप में महंगा बना रही है, एक तरह से भद्दा होता है।

उत्तर

20

जब से तुम उल्लेख IEnumerable[<T>] (नहीं IList[<T>] आदि), हम में गिना जाता है आदि पर भरोसा नहीं कर सकते हैं: तो मैं उतारना करने के लिए foreach परीक्षा की जाएगी:

using(var iter = source.GetEnumerator()) { 
    if(iter.MoveNext()) { 
     T last = iter.Current; 
     while(iter.MoveNext()) { 
      // here, "last" is a non-final value; do something with "last" 
      last = iter.Current; 
     } 
     // here, "last" is the FINAL one; do something else with "last" 
    } 
} 

नोट ऊपर तकनीकी रूप से केवल के लिए मान्य है IEnuemerable<T>; गैर सामान्य के लिए, आप आवश्यकता होगी:

var iter = source.GetEnumerator(); 
using(iter as IDisposable) { 
    if(iter.MoveNext()) { 
     SomeType last = (SomeType) iter.Current; 
     while(iter.MoveNext()) { 
      // here, "last" is a non-final value; do something with "last" 
      last = (SomeType) iter.Current; 
     } 
     // here, "last" is the FINAL one; do something else with "last" 
    } 
} 
+0

धन्यवाद मैं डाल कि एक विस्तार विधि में https://gist.github.com/2781446 –

+0

@OJay नहीं; एक बार जब हम जानते हैं कि यह अंतिम * तत्व नहीं है, तो पहले तत्व को संसाधित किया जाता है, इसलिए: जब हमने दूसरा पढ़ा है - ध्यान दें कि पहली टिप्पणी में हम 'अंतिम' के साथ काम करते हैं, उर्फ ​​** पिछले ** आइटम, * नहीं * वर्तमान एक –

+0

'IENuemerable' को अनुमान लगाया जाना चाहिए 'Inumerable' मुझे लगता है। – Blairg23

1

आप के रूप में कुशलता से ऐसा करना चाहते हैं, तो संभव के रूप में वहाँ प्रभावी ढंग से न केवल वर्तमान बल्कि "अगला" या "पिछला" को देख के अलावा कोई अन्य विकल्प है आइटम, ताकि आप उस जानकारी के बाद क्या करना है इसके निर्णय को रोक सकते हैं।

if (collection.Any()) { 
    var seenFirst = false; 
    T prev = default(T); 
    foreach (var current in collection) { 
     if (seenFirst) Foo(prev); 
     seenFirst = true; 
     prev = current; 
    } 
    Bar(prev); 
} 

See it in action: उदाहरण के लिए, यह सोचते हैं T संग्रह में आइटम के प्रकार है।

+0

रिवर्स और tolist दोनों बफरिंग आपरेशनों रहे हैं ... एक लंबे दृश्य के लिए, यह वास्तव में बहुत दर्दनाक हो सकता है। –

+0

@MarcGravell: बिल्कुल।मैंने पहले त्वरित और गंदे समाधान देने के लिए सोचा था और अच्छा आखिरी वाला था, लेकिन यह पता चला कि अच्छा एक खिड़की से बाहर नहीं है जितनी खिड़की वे जाते हैं। :) – Jon

+0

यह अच्छा है; पी –

0

मैं वास्तव में यह सिफारिश नहीं होगा, लेकिन मुझे लगता है कि आप इस तरह से कुछ कर सकते हैं ...

object m_item = notPartOfListFlag = new object(); 
foreach(var item in enumerator){ 
    if(m_item != notPartOfListFlag) 
    { 
     //do stuff to m_item; 
    } 
    m_item = item; 
} 
//do stuff to last item aka m_item; 

लेकिन मुझे लगता है कि में आइटम की स्थिति को उजागर करता है संग्रह के कुछ प्रकार का उपयोग करने की कोशिश करेंगे सूची है, तो यकीन है कि मुझे यह पसंद है कि जिस तरह से जब आप अंत आप 'करने के लिए मिल का उपयोग

if(collection.IndexOf(item) == collection.Count-1) do stuff 
+0

'शून्य 'एक पूरी तरह से वैध मान है ... –

+0

यह सच है, मुझे एक सेकंड दें और मैं इसे इसके लिए खाते में अपडेट कर दूंगा। – JonC

0

नहीं 100% लेकिन आप हमेशा आइटम के उपयोग में देरी हो सकती जब तक आप IEnumerable सरणी में एक कदम स्थानांतरित कर दिया है, पिछली प्रविष्टि का उपयोग नहीं किया है।

यह प्रगणक पर एक गणना के लिए मजबूर करने के लिए टाल।

object item = null; 
foreach (var a in items) 
{ 
    // if item is set then we can use it. 
    if (item != null) 
    { 
     // not final item 
     f(item); 
    } 
    item = a; 
} 

// final item. 
g(item); 
+1

'null' पूरी तरह से वैध मान हो सकता है ... –

+0

प्रारंभिक मान वास्तव में शून्य नहीं होना चाहिए, आप इसे किसी भी चीज़ पर सेट कर सकते हैं जो वैध मान नहीं है और केवल यह जांचें कि यह उसके बराबर नहीं है। या यह पहला फ्लॉप कहने के लिए ध्वज का उपयोग करें। – Andy

+0

यह संभव है कि कोई अमान्य मान न हो। – Servy

2

मार्क के उत्तर के समान, लेकिन आप इसे लपेटने के लिए एक विस्तार विधि लिख सकते हैं।

public static class LastEnumerator 
{ 
    public static IEnumerable<MetaEnumerableItem<T>> GetLastEnumerable<T>(this IEnumerable<T> blah) 
    { 
     bool isFirst = true; 
     using (var enumerator = blah.GetEnumerator()) 
     { 
      if (enumerator.MoveNext()) 
      { 
       bool isLast; 
       do 
       { 
        var current = enumerator.Current; 
        isLast = !enumerator.MoveNext(); 
        yield return new MetaEnumerableItem<T> 
         { 
          Value = current, 
          IsLast = isLast, 
          IsFirst = isFirst 
         }; 
        isFirst = false; 
       } while (!isLast); 
      } 
     } 

    } 
} 

public class MetaEnumerableItem<T> 
{ 
    public T Value { get; set; } 
    public bool IsLast { get; set; } 
    public bool IsFirst { get; set; } 
} 

तो इतना है कि यह फोन:

foreach (var row in records.GetLastEnumerable()) 
{ 
    output(row.Value); 
    if(row.IsLast) 
    { 
     outputLastStuff(row.Value); 
    } 
} 
संबंधित मुद्दे