.net의 IEnumerable <T>에서 첫 번째 요소를 얻는 방법은 무엇입니까?


156

나는 종종 in.net의 첫 번째 요소를 잡고 싶고 IEnumerable<T>좋은 방법을 찾지 못했습니다. 내가 생각해 낸 최선은 다음과 같습니다.

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

왝! 이렇게하는 좋은 방법이 있습니까?

답변:


241

LINQ를 사용할 수있는 경우 다음을 사용할 수 있습니다.

var e = enumerable.First();

열거 형이 비어있는 경우 예외가 발생합니다.이 경우 다음을 사용할 수 있습니다.

var e = enumerable.FirstOrDefault();

FirstOrDefault()default(T)열거 형이 비어있는 경우 반환 됩니다.이 null형식은 참조 형식이거나 값 형식의 기본 '0 값'입니다.

LINQ를 사용할 수없는 경우 기술적으로 정확하고 GetEnumeratorand MoveNext메소드를 사용하여 열거자를 작성 하여 첫 번째 결과를 검색하는 것 (이 예에서는 열거 가능한 것이이라고 가정) 과 다르지 않습니다 IEnumerable<Elem>.

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

.Single()의견에 Joel Coehoorn이 언급 되었습니다. 열거 형에 정확히 하나의 요소가 포함될 것으로 예상되는 경우에도 작동합니다. 그러나 비어 있거나 하나 이상의 요소 인 경우 예외가 발생합니다. SingleOrDefault()이와 유사한 방식으로이 시나리오를 다루는 해당 방법이 있습니다 FirstOrDefault(). 그러나 David BSingleOrDefault()열거 형에 둘 이상의 항목이 포함 된 경우 여전히 예외 가 발생할 수 있다고 설명합니다 .

편집 : Marc Gravell 에게 IEnumerator객체를 사용한 후에 폐기해야한다고 지적 해 주셔서 감사 합니다 using.이 패턴을 구현하기 위해 키워드를 표시하도록 LINQ 이외의 예를 편집했습니다 .


2
SingleOrDefault는 1을 반환한다는 점을 지적 할 가치가 있습니다. 2) 항목이 없으면 null입니다. 3) 둘 이상의 항목이 있으면 예외를 던집니다.
Amy 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

2.0을 사용 중이라면 var도 없습니다.
재귀

1
글쎄요, 만약 당신이 화를
내고 싶다면

.NET 2.0을 사용하는 사람에게는 매우 감사했습니다! 명성.
kayleeFrye_onDeck

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를 호출하지 않아야합니다. IDisposable을 구현하면 foreach가 열거자를 처리합니다. MoveNext 및 Current를 호출 할 때는 수동으로 처리해야합니다 (적용 가능한 경우).


1
열거자를 피해야한다는 증거는 무엇입니까? 내 컴퓨터의 성능 테스트에 따르면 foreach보다 약 10 % 정도 성능이 향상되었습니다.
BenAlabaster

그것은 당신이 열거하고있는 것에 달려 있습니다. Erumerator는 데이터베이스에 대한 연결을 닫고 파일 핸들을 닫고 닫고 잠긴 객체를 해제 할 수 있습니다. 정수 목록의 열거자를 배치하지 않으면 해롭지 않을 것입니다.
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;
}

0

ith 요소를 제공하는보다 일반적인 버전을 사용해 볼 수도 있습니다.

enumerable.ElementAtOrDefault (i));

그것이 도움이되기를 바랍니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.