答案 0 :(得分:85)
通过在IEnumerable<T>
上调用Count,我假设您在Count
上引用了扩展方法System.Linq.Enumerable
。 Length
不是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会通过人员进行四次检查,检查部门负责人,按名称对其进行排序,然后计算结果对象。
只有当人员和部门是预设值集合而不是查询本身时才会这样。