如何从.net中的IEnumerable <T>获取第一个元素?


156

我经常想抓住IEnumerable<T>.net 的第一个元素,但是我还没有找到一种很好的方法。我想出的最好的是:

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

!那么,有没有很好的方法可以做到这一点?

Answers:


241

如果可以使用LINQ,则可以使用:

var e = enumerable.First();

尽管如果enumerable为空,则将引发异常:在这种情况下,您可以使用:

var e = enumerable.FirstOrDefault();

FirstOrDefault()default(T)如果可枚举为空,则将返回null用于引用类型,对于值类型默认的“零值”。

如果您不能使用LINQ,那么您的方法在技术上是正确的,并且与使用GetEnumeratorMoveNext方法创建枚举器以检索第一个结果没有什么不同(此示例假定enumerable是一个IEnumerable<Elem>):

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

Joel Coehoorn.Single()在评论中提到;如果您希望枚举数仅包含一个元素,那么这也将起作用-但是,如果它为空或大于一个元素,它将抛出异常。有一种对应的SingleOrDefault()方法以与相似的方式涵盖了这种情况FirstOrDefault()。但是,David B解释说SingleOrDefault()在可枚举包含多个项目的情况下,仍然可能会引发异常。

编辑:感谢Marc Gravell指出IEnumerator使用该对象后需要处理我的对象-我已经编辑了非LINQ示例以显示using用于实现此模式的关键字。


2
值得指出的是,SingleOrDefault将返回1)如果只有一项,则为唯一项。2)如果没有项目,则为null。3)如果有多个项目,则引发异常。
艾米B

打个招呼David 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
好吧,我想如果你想挑剔的话,我会正确声明的:P
BenAlabaster

作为坚持使用.NET 2.0的人,对此深表感谢!荣誉
kayleeFrye_onDeck 2015年



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

这取决于您要枚举的内容。枚举器可以关闭与数据库的连接,刷新并关闭文件句柄,释放一些锁定的对象,等等。我猜想,不设置某个整数列表的枚举器不会造成危害。
2009年

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

希望能帮助到你

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.