2014-04-01 18 views
7

मान लीजिए मैं एक IEnumerable<T> है, और मुझे पहला तत्व लेने के लिए और कुछ अन्य कोड के लिए शेष तत्व पास करना चाहते हैं। मैं Take(n) का उपयोग कर पहली n तत्वों प्राप्त कर सकते हैं, लेकिन कैसे मैं तो गणना फिर से शुरू करने के लिए पैदा करने के बिना शेष तत्वों का उपयोग कर सकते हैं?क्या मैं पहले एन तत्वों को एक गणना से ले सकता हूं, और फिर भी शेष गणना का उपयोग कर सकता हूं?

उदाहरण के लिए, मान लीजिए कि मेरे पास एक विधि ReadRecords है जो CSV फ़ाइल में रिकॉर्ड को IEnumerable<string> के रूप में स्वीकार करता है। अब मान लीजिए कि उस विधि के भीतर, मैं पहला रिकॉर्ड (हेडर) पढ़ना चाहता हूं, और उसके बाद शेष रिकॉर्ड ReadDataRecords विधि को पास करता हूं जो IEnumerable<string> भी लेता है। इस तरह:

void ReadCsv(IEnumerable<string> records) 
{ 
    var headerRecord = records.Take(1); 
    var dataRecords = ??? 

    ReadDataRecords(dataRecords); 
} 

void ReadDataRecords(IEnumerable<string> records) 
{ 
    // ... 
} 

अगर मैं गणन फिर से शुरू करने के लिए तैयार थे, तो मैं dataRecords = records.Skip(1) इस्तेमाल कर सकते हैं। हालांकि, मैं इसे फिर से शुरू नहीं करना चाहता - वास्तव में, यह फिर से शुरू नहीं हो सकता है।

तो, वहाँ किसी भी तरह से पहले रिकॉर्ड लेने के लिए शेष रिकॉर्ड (एक नया संग्रह और उन्हें फिर से गणना में सभी मूल्यों को पढ़ने के अतिरिक्त) है, और फिर?

+2

यदि आपको केवल एक को छोड़ने की आवश्यकता है तो बड़ा सौदा क्या है? बस फिर से गिनती और एक छोड़ दो? – Paparazzi

+0

वहाँ MoreLinq में अच्छा समाधान है कि आप कुछ [बैचिंग समर्थन] की जरूरत है (http://stackoverflow.com/questions/13731796/create-batches-in-linq)। विशेष आवरण पहले/अंतिम तत्व के बारे में भी कई प्रश्न हैं। –

+0

@ बलाम: यदि गणना सूची में वस्तुओं पर गणना करने जैसे कुछ स्मृति में गणना करके बनाई गई थी, तो हाँ। लेकिन क्या होगा यदि गणना फिर से शुरू नहीं की जा सकती है, या निष्पादित करने के लिए बहुत महंगा है? मैं नहीं देखता कि दो अंक होने के लिए क्यों जरूरी होना चाहिए जब मैं केवल एक ही आइटम को एक बार लाने के लिए चाहता हूं। –

उत्तर

13

यह एक दिलचस्प सवाल है, मुझे लगता है कि है आप के बजाय LINQ का उपयोग कर के, इस तरह एक समाधान का उपयोग कर सकते प्रगणक हो और इसका इस्तेमाल करते हैं:

private void ReadCsv(IEnumerable<string> records) 
{ 
    var enumerator = records.GetEnumerator(); 
    enumerator.MoveNext(); 
    var headerRecord = enumerator.Current; 
    var dataRecords = GetRemainingRecords(enumerator); 
} 

public IEnumerable<string> GetRemainingRecords(IEnumerator<string> enumerator) 
{ 
    while (enumerator.MoveNext()) 
    { 
     if (enumerator.Current != null) 
      yield return enumerator.Current; 
    } 
} 

अद्यतन: यहाँ अपनी टिप्पणी के अनुसार अधिक बढ़ाया है ऐसा करने का तरीका:

public static class CustomEnumerator 
{ 
    private static int _counter = 0; 
    private static IEnumerator enumerator; 
    public static IEnumerable<T> GetRecords<T>(this IEnumerable<T> source) 
    { 
     if (enumerator == null) enumerator = source.GetEnumerator(); 

     if (_counter == 0) 
     { 
      enumerator.MoveNext(); 
      _counter++; 
      yield return (T)enumerator.Current; 
     } 
     else 
     { 
      while (enumerator.MoveNext()) 
      { 
       yield return (T)enumerator.Current; 
      } 
      _counter = 0; 
      enumerator = null; 
     } 
    } 
} 

उपयोग:

private static void ReadCsv(IEnumerable<string> records) 
{ 
    var headerRecord = records.GetRecords(); 
    var dataRecords = records.GetRecords(); 
} 
+0

@TyCobb संपादन के लिए धन्यवाद। –

+0

कोई जांच नहीं। मुझे याद दिलाने के लिए धन्यवाद कि एन्युमरेटर्स अभी भी सभी प्यारे वाक्यविन्यास के शीर्ष पर मौजूद हैं जो ढांचे में जोड़े जा रहे हैं और समय-समय पर उपयोग करने के लिए अभी भी अच्छे हो सकते हैं। +1 – TyCobb

+0

धन्यवाद। मुझे लगता है कि मैं IENumerable के लिए शेष प्राप्त करने के लिए एक सामान्य उद्देश्य वर्ग बना सकता हूं। बीटीडब्ल्यू, लूप में शून्य परीक्षण क्यों? अनावश्यक लगता है ... –

3

हाँ, IEnumerable से IEnumerator उपयोग करें, और आप विधि कॉल भर में स्थिति को बनाए रखने कर सकते हैं;

एक साधारण उदाहरण;

public class Program 
{ 
    static void Main(string[] args) 
    { 
     int[] arr = new [] {1, 2, 3}; 
     IEnumerator enumerator = arr.GetEnumerator(); 
     enumerator.MoveNext(); 
     Console.WriteLine(enumerator.Current); 
     DoRest(enumerator); 
    } 

    static void DoRest(IEnumerator enumerator) 
    { 
     while (enumerator.MoveNext()) 
      Console.WriteLine(enumerator.Current); 
    } 
} 
+0

धन्यवाद, लेकिन मैं वास्तव में एक ऐसी विधि को कॉल करने में सक्षम होना चाहता था जो आईनेमेरेबल लेता है ताकि एक अच्छा एपीआई संरक्षित किया जा सके। क्षमा करें मैंने इसे बहुत स्पष्ट नहीं किया। –

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

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