मैं IEnumerable <T> से .net में पहला तत्व कैसे प्राप्त करूं?


156

मैं अक्सर एक IEnumerable<T>.net के पहले तत्व को हथियाना चाहता हूं , और मुझे ऐसा करने का अच्छा तरीका नहीं मिला। सबसे अच्छा मैं आया हूँ:

foreach(Elem e in enumerable) {
  // do something with e
  break;
}

नीरस तो, क्या ऐसा करने का एक अच्छा तरीका है?

जवाबों:


241

यदि आप LINQ का उपयोग कर सकते हैं तो आप उपयोग कर सकते हैं:

var e = enumerable.First();

यह एक अपवाद फेंक देगा, हालांकि अगर गणना योग्य खाली है: जिस स्थिति में आप उपयोग कर सकते हैं:

var e = enumerable.FirstOrDefault();

FirstOrDefault()default(T)अगर वापसी योग्य है, जो nullसंदर्भ प्रकारों के लिए या डिफ़ॉल्ट प्रकारों के लिए डिफ़ॉल्ट 'शून्य-मान' के लिए होगी।

यदि आप LINQ का उपयोग नहीं कर सकते हैं, तो आपका दृष्टिकोण तकनीकी रूप से सही है और पहला परिणाम प्राप्त करने के तरीकों GetEnumeratorऔर MoveNextविधियों का उपयोग करके एक एन्यूमरेटर बनाने से अलग नहीं है (यह उदाहरण मान लेता है कि ए IEnumerable<Elem>) उपयुक्त है:

Elem e = myDefault;
using (IEnumerator<Elem> enumer = enumerable.GetEnumerator()) {
    if (enumer.MoveNext()) e = enumer.Current;
}

जोएल कोएहॉर्न ने .Single()टिप्पणियों में उल्लेख किया है; यह भी काम करेगा, यदि आप अपने गणना करने योग्य से एक तत्व को शामिल करने की उम्मीद कर रहे हैं - हालांकि यह एक अपवाद को फेंक देगा यदि यह एक तत्व से या तो खाली है या बड़ा है। एक समान SingleOrDefault()विधि है जो इस परिदृश्य को इसी तरह से कवर करती है FirstOrDefault()। हालांकि, डेविड बी बताते हैं कि SingleOrDefault()अभी भी उस मामले में एक अपवाद को फेंक सकते हैं जहां गणना करने योग्य में एक से अधिक आइटम होते हैं।

संपादित करें: मार्क ग्रेवेल को यह इंगित करने के लिए कि मुझे IEnumeratorइसका उपयोग करने के बाद अपनी वस्तु का निपटान करने की आवश्यकता है - मैंने usingइस पैटर्न को लागू करने के लिए कीवर्ड प्रदर्शित करने के लिए गैर-LINQ उदाहरण संपादित किया है ।


2
एक ओर लौटने की ओर इशारा करते हुए कहा गया है कि सिंगलऑर्डेफ़ॉल्ट 1) केवल एक आइटम होने पर वापस आ जाएगा। 2) शून्य अगर कोई आइटम नहीं हैं। 3) एक से अधिक आइटम होने पर एक अपवाद को फेंक दें।
एमी बी

अच्छी कॉल डेविड बी - एक नोट जोड़ा।
एरिक फोर्ब्स

36

बस मामले में आप .NET 2.0 का उपयोग कर रहे हैं और LINQ तक पहुंच नहीं है:

 static T First<T>(IEnumerable<T> items)
 {
     using(IEnumerator<T> iter = items.GetEnumerator())
     {
         iter.MoveNext();
         return iter.Current;
     }
 }

यह वही करना चाहिए जो आप खोज रहे हैं ... यह जेनेरिक का उपयोग करता है ताकि आप किसी भी प्रकार IEnumerable पर पहला आइटम प्राप्त कर सकें।

इसे ऐसे कॉल करें:

List<string> items = new List<string>() { "A", "B", "C", "D", "E" };
string firstItem = First<string>(items);

या

int[] items = new int[] { 1, 2, 3, 4, 5 };
int firstItem = First<int>(items);

आप इसे आसानी से संशोधित कर सकते हैं। .NET 3.5 का IEnumerable.ElementAt () एक्सटेंशन विधि की नकल करने के लिए पर्याप्त है:

static T ElementAt<T>(IEnumerable<T> items, int index)
{
    using(IEnumerator<T> iter = items.GetEnumerator())
    {
        for (int i = 0; i <= index; i++, iter.MoveNext()) ;
        return iter.Current;
    }
} 

इसे इस तरह से कॉल करना:

int[] items = { 1, 2, 3, 4, 5 };
int elemIdx = 3;
int item = ElementAt<int>(items, elemIdx);

बेशक, यदि आपके पास LINQ तक पहुंच है, तो पहले से ही बहुत सारे अच्छे उत्तर हैं ...


ओह, निश्चित रूप से आप सही हैं, धन्यवाद। मैंने अपने उदाहरणों को सही किया है।
बेनालास्टर

यदि आप 2.0 पर हैं, तो आपके पास var नहीं है।
पुनरावर्ती

1
वैसे मुझे लगता है कि अगर आप चुस्त हो जाना चाहते हैं तो मैं उन्हें ठीक तरह से घोषित कर दूंगा: पी
बेनालास्टर

किसी ऐसे व्यक्ति के रूप में जो .NET 2.0 का उपयोग कर रहा है, इसे बहुत सराहना मिली! कुडोस।
kayleeFrye_onDeck

26

खैर, आपने यह निर्दिष्ट नहीं किया कि आप किस .Net के किस संस्करण का उपयोग कर रहे हैं।

मान लें कि आपके पास 3.5 है, तो एक और तरीका एलीमेंट विधि है:

var e = enumerable.ElementAt(0);

2
ElementAt (0), अच्छा और सरल।
JMD


1

इसे इस्तेमाल करे

IEnumberable<string> aa;
string a = (from t in aa where t.Equals("") select t.Value).ToArray()[0];

0

पहले से बताए गए अनुसार FirstOrDefault या एक foreach पाश का उपयोग करें। एक एन्यूमरेटर को मैन्युअल रूप से लाने और करंट से बचने से बचना चाहिए। यदि यह IDis प्रयोज्य लागू करता है, तो foreach आपके लिए आपके एन्यूमरेटर को निष्क्रिय कर देगा। MoveNext और Current को कॉल करते समय आपको इसे मैन्युअल रूप से डिस्पोज़ करना होगा (यदि aplicable)।


1
क्या सबूत है कि प्रगणक से बचा जाना चाहिए? मेरी मशीन पर प्रदर्शन परीक्षणों से संकेत मिलता है कि इसके पास लगभग 10% प्रदर्शन लाभ है।
बेनालास्टर

यह निर्भर करता है कि आप क्या कर रहे हैं। एक Erumerator डेटाबेस से कनेक्शन बंद कर सकता है, fush और क्लोज़ फ़ाइल हैंडल, कुछ लॉक्ड ऑब्जेक्ट्स को रिलीज़ करता है, आदि। कुछ पूर्णांक सूची के एन्यूमरेटर को डिस्पोज़ करना हानिरहित नहीं होगा, मुझे लगता है।
मूक

0

यदि आपका IEnumerable इसे उजागर नहीं करता है <T>और Linq विफल रहता है, तो आप प्रतिबिंब का उपयोग करके एक विधि लिख सकते हैं:

public static T GetEnumeratedItem<T>(Object items, int index) where T : class
{
  T item = null;
  if (items != null)
  {
    System.Reflection.MethodInfo mi = items.GetType()
      .GetMethod("GetEnumerator");
    if (mi != null)
    {
      object o = mi.Invoke(items, null);
      if (o != null)
      {
        System.Reflection.MethodInfo mn = o.GetType()
          .GetMethod("MoveNext");
        if (mn != null)
        {
          object next = mn.Invoke(o, null);
          while (next != null && next.ToString() == "True")
          {
            if (index < 1)
            {
              System.Reflection.PropertyInfo pi = o
                .GetType().GetProperty("Current");
              if (pi != null) item = pi
                .GetValue(o, null) as T;
              break;
            }
            index--;
          }
        }
      }
    }
  }
  return item;
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.