IEnumerable Count()和Length之间的差异

时间:2010-03-26 07:05:15

标签: c# .net ienumerable

3 个答案:

答案 0 :(得分:85)

通过在IEnumerable<T>上调用Count,我假设您在Count上引用了扩展方法System.Linq.EnumerableLength不是IEnumerable<T>上的方法,而是.Net中数组类型的属性,例如int[]

不同之处在于表现。 Length属性保证是O(1)操作。 Count扩展方法的复杂性因对象的运行时类型而异。它将尝试通过ICollection<T>属性转换为支持O {1)长度查找的几种类型,如Count。如果没有可用的话,它将枚举所有项目并计算它们的复杂度为O(N)。

例如

int[] list = CreateSomeList();
Console.WriteLine(list.Length);  // O(1)
IEnumerable<int> e1 = list;
Console.WriteLine(e1.Count()); // O(1) 
IEnumerable<int> e2 = list.Where(x => x <> 42);
Console.WriteLine(e2.Count()); // O(N)

e2实现为不支持O(1)计数的C#迭代器,因此方法Count必须枚举整个集合以确定它的持续时间。

答案 1 :(得分:20)

答案 2 :(得分:1)

  • 长度是固定属性,例如一维数组或字符串。因此,从来没有必要的计数操作(多维数组的所有维度的大小相乘)。这里的O(1)操作意味着无论有多少元素,检索时间总是相同的。线性搜索(与此相反)是O(n)。

  • ICollections上的Count属性(例如List和List&lt; T&gt;)可以更改,因此要么在添加/删除操作上更新,要么在Collection更改后请求Count时更新。取决于对象的实现。

  • LINQ的Count()方法基本上每次调用它都会迭代(除非对象是ICollection类型,然后请求ICollection.Count属性)。

请注意,IEnumerables通常不是已定义的对象集合(如列表,数组,哈希表等),而是链接到后台操作,后者在请求时生成结果(称为延迟执行)。

通常,您有像这样的LINQ语句(延迟执行的典型应用程序):

IEnumerable<Person> deptLeaders = 
   from p in persons
   join d in departments
      on p.ID equals d.LeaderID
   orderby p.LastName, p.FirstName
   select p;

然后,有这样的代码:

if (deptLeaders.Count() > 0)
{
   ReportNumberOfDeptLeaders(deptLeaders.Count());
   if (deptLeaders.Count() > 20)
      WarnTooManyDepartmentLeaders(deptLeaders.Count());
}

因此,当发出太多部门负责人的警告时,.NET会通过人员进行四次检查,检查部门负责人,按名称对其进行排序,然后计算结果对象。

只有当人员和部门是预设值集合而不是查询本身时才会这样。