<Collection> .Count是否使用昂贵?

Bob*_*man 23 c# collections count

我正在编写一个缓存弹出方法,基本上看起来像这样:

while ( myHashSet.Count > MAX_ALLOWED_CACHE_MEMBERS )
{
    EjectOldestItem( myHashSet );
}
Run Code Online (Sandbox Code Playgroud)

我的问题是关于如何Count确定:它只是一个privateprotected int,或者它是通过每次调用时计算元素来计算的?

Vla*_*lad 44

来自http://msdn.microsoft.com/en-us/library/ms132433.aspx:

检索此属性的值是O(1)操作.

这保证了访问Count权限不会遍历整个集合.


编辑:正如许多其他海报所建议的那样,IEnumerable<...>.Count()保证是O(1).小心使用!

IEnumerable<...>.Count()是一个定义的扩展方法System.Linq.Enumerable.如果count IEnumerable<T>确实是一个实例,则当前实现进行显式测试ICollection<T>,并ICollection<T>.Count在可能的情况下使用.否则它会遍历IEnumerable<T>(可能进行延迟评估扩展)并逐项计算项目.

然而,我没有在文档中发现是否可以保证IEnumerable<...>.Count()使用O(1),我只使用Reflector检查了.NET 3.5中的实现.


必要的后期添加:许多流行的容器不是派生出来的Collection<T>,但是它们的Count属性是O(1)(也就是说,不会迭代整个集合).例子是HashSet<T>.Count(这个人是最有可能的OP想问什么)Dictionary<K, V>.Count,LinkedList<T>.Count,List<T>.Count,Queue<T>.Count,Stack<T>.Count等.

所有这些集合都实现ICollection<T>或只是ICollection,因此它们CountICollection<T>.Count(或ICollection.Count)的实现.ICollection<T>.Count根据文档,实现O(1)操作不是必需的,但上面提到的操作是这样做的.

(请注意:例如,某些容器Queue<T>实现非泛型ICollection但不实现ICollection<T>,因此它们Count仅从from "继承"该属性ICollection.)

  • 请注意,还有一个适用于IEnumerables的Count()扩展方法.那不是*保证是O(1). (5认同)
  • 别客气.虽然我们在这里,但我可能也应该提到.Any()是一个比.Count()== 0更好的选择,原因很明显. (3认同)
  • 应该采取我自己的建议并阅读Collection <T> .Count而不仅仅是List <T> .Count文档!谢谢. (2认同)

Nic*_*ick 9

您的问题未指定特定的 Collection类,因此......

这取决于Collection类.ArrayList有一个跟踪计数的内部变量,List也是如此.但是,它是特定于实现的,并且根据集合的类型,理论上可以在每次调用时重新计算.

  • @John - 很难说出因为他如何措辞这个头衔.<Collection>是否意味着是任何集合类的通用占位符,或者它是否是实际的"Collection"类. (4认同)

Axe*_*ger 7

它是一个内部值,不计算.该文档指出获取值是O(1)的操作.


Jos*_*osh 6

正如其他人所说,修改集合时会保留Count.框架中的每个集合类型几乎都是这种情况.这与在IEnumerable上使用Count扩展方法有很大不同,IEnumerable每次都会枚举集合.

此外,对于较新的集合类,Count属性不是虚拟的,这意味着抖动可以内联对Count访问器的调用,这使得它实际上与访问字段相同.换句话说,非常快.