我正在编写一个基本上看起来像这样的缓存弹出方法:
while ( myHashSet.Count > MAX_ALLOWED_CACHE_MEMBERS )
{
EjectOldestItem( myHashSet );
}
我的问题是如何确定Count
:它只是private
还是protected int
,还是通过每次调用时计算元素来计算?
答案 0 :(得分:44)
来自http://msdn.microsoft.com/en-us/library/ms132433.aspx:
检索此属性的值是O(1)操作。
这可以保证访问Count
不会遍历整个集合。
编辑:正如许多其他海报所建议的那样,IEnumerable<...>.Count()
然而 保证不是O(1)。小心使用!
IEnumerable<...>.Count()
是System.Linq.Enumerable
中定义的扩展方法。如果计算的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
,{{3}等等。
所有这些集合都实现ICollection<T>
或仅ICollection
,因此他们的Count
是Stack<T>.Count
(或ICollection<T>.Count
)的实现。根据文档,ICollection<T>.Count
的实现不需要是O(1)操作,但上面提到的操作是这样做的。
(请注意:某些容器,例如,ICollection.Count
,实现非通用ICollection
但不实现ICollection<T>
,因此它们仅从“{1}}”继承“Count
属性来自ICollection
。)
答案 1 :(得分:9)
您的问题未指定特定的集合类,因此......
这取决于Collection类。 ArrayList有一个跟踪计数的内部变量,List也是如此。但是,它是特定于实现的,并且根据集合的类型,理论上可以在每次调用时重新计算。
答案 2 :(得分:7)
这是一个内部值,不计算。 documentation表示获取值是O(1)操作。
答案 3 :(得分:6)
正如其他人所说,修改集合时会保留Count。框架中的每个集合类型几乎都是这种情况。这与在IEnumerable上使用Count扩展方法有很大不同,IEnumerable每次都会枚举该集合。
此外,对于较新的集合类,Count属性不是虚拟的,这意味着抖动可以内联对Count访问器的调用,这使得它实际上与访问字段相同。换句话说,非常快。
答案 4 :(得分:4)
如果是HashSet
,它只是一个内部int
字段,甚至SortedSet
(基于二进制树的.net 4设置)都在内部字段中计数。
答案 5 :(得分:3)
根据Reflector,它实现为
public int Count{ get; }
因此它由派生类型
定义答案 6 :(得分:2)
快速说明一下。在使用System.Linq时,有两种方法可以在.NET 3.5中计算集合。对于普通集合,第一个选择应该是使用Count属性,原因已在其他答案中描述过。
还可以通过LINQ .Count()扩展方法获得替代方法。关于.Count()的有趣之处在于它可以在任何可枚举上调用,无论底层类是否实现ICollection,或者它是否具有Count属性。但是,如果您曾调用过.Count(),请注意它会迭代集合以动态生成计数。这通常会导致O(n)复杂性。
我想要注意的唯一原因是,使用IntelliSense,通常很容易意外地使用Count()扩展而不是Count属性。
答案 7 :(得分:1)
每次将新项目添加到集合时,内部int
都会增加。