.netのIEnumerable <T>から最初の要素を取得するにはどうすればよいですか?


157

IEnumerable<T>.netの最初の要素を取得したいことがよくありますが、それを行うための良い方法が見つかりませんでした。私が思いついた最高のものは:

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

おい!それで、これを行う良い方法はありますか?

回答:


242

LINQを使用できる場合は、以下を使用できます。

var e = enumerable.First();

ただし、enumerableが空の場合は例外がスローされます。その場合は次のように使用できます。

var e = enumerable.FirstOrDefault();

FirstOrDefault()default(T)列挙型が空の場合に返されます。これはnull、参照型の場合、または値型のデフォルトの「ゼロ値」の場合です。

LINQを使用できない場合、アプローチは技術的に正しく、GetEnumeratorand MoveNextメソッドを使用して最初の結果を取得する列挙子を作成することと同じです(この例では、列挙可能はであると想定していますIEnumerable<Elem>)。

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

Joel Coehoorn.Single()がコメントで言及しました。これは、列挙可能要素に正確に1つの要素が含まれることを期待している場合にも機能します。ただし、要素が空であるか、1つの要素よりも大きい場合は、例外がスローされます。SingleOrDefault()と同様の方法でこのシナリオをカバーする対応するメソッドがありFirstOrDefault()ます。ただし、David BSingleOrDefault()、列挙型に複数のアイテムが含まれている場合でも例外がスローされる可能性があると説明しています。

編集:使用後にオブジェクトを破棄する必要があることを指摘してくれたMarc Gravellに感謝IEnumeratorしますusing。このパターンを実装するためのキーワードを表示するように非LINQの例を編集しました。


2
SingleOrDefaultは1)を返すことを指摘する価値があります。アイテムが1つしかない場合は、唯一のアイテムです。2)アイテムがない場合はnull。3)複数のアイテムがある場合は、例外をスローします。
エイミーB

グッドコールデビッドB-メモを追加しました。
Erik Forbes

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にアクセスできる場合、すでにたくさんの良い答えが投稿されています...


おっと、もちろんあなたは正しい、ありがとう。例を修正しました。
BenAlabaster、2009年

2.0を使用している場合は、varもありません。
再帰的

1
まあ、あなたが気難しいことになりたければ、私はそれらを適切に宣言します:P
BenAlabaster 2009年

.NET 2.0を使用して立ち往生している人として、これは大いに感謝されました!称賛。
kayleeFrye_onDeck 2015年

26

使用している.Netのバージョンを指定していません。

あなたが3.5を持っていると仮定すると、別の方法はElementAtメソッドです:

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ループを使用します。列挙子を手動でフェッチしてCurrentを呼び出すことは避けてください。foreachは、IDisposableを実装している場合、列挙子を破棄します。MoveNextとCurrentを呼び出すときは、手動で破棄する必要があります(該当する場合)。


1
列挙子を避けるべきであるという証拠はありますか?私のマシンでのパフォーマンステストでは、foreachよりもパフォーマンスが約10%向上していることが示されています。
BenAlabaster、2009年

何を列挙するかによります。Erumeratorは、データベースへの接続を閉じたり、ファイルハンドルをfushして閉じたり、ロックされたオブジェクトを解放したりすることができます。整数リストの列挙子を破棄しなくても害はありません。
Mouk

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;
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.