Count和Capacity有多快?

11

我经常写这样的代码:

if ( list.Count > 0 ) { }

这样做效率高吗?操作是否像这样:

  • 遍历列表并计算其元素数量
  • 结果:986,000 个元素
  • 986,000 是否大于 0?
  • 返回 true

还是像这样:

  • 检索列表中存储的元素数量(986,000)
  • 986,000 是否大于 0?
  • 返回 true

也就是说,获取列表元素的数量,是否需要完全遍历列表,或者元素数量记录在某处?所有 ICollection 类都是这种情况吗?

那么列表的 Capacity 呢?

5个回答

33
我经常写这样的代码:if ( list.Count > 0 ) { } 这样有效吗?
是的。这会检索列表中存储在字段内的计数,并将其与零进行比较。
现在有一个你没有问过的问题: if ( sequence.Count() > 0 ) { } 怎么样?(注意 Count() 上的括号。)
我们在运行时查询序列,以查看它是否是具有可以高效计算的 Count 属性的列表。 如果是,则调用它。 如果不是,则逐个计算整个序列,然后将其与零进行比较。
这不是非常低效吗?
是的。
更高效的方法是什么? if (sequence.Any()) 为什么这样更高效?
因为它尝试迭代一个元素。如果成功,则 Any 是 true;如果失败,则 Any 是 false。要知道罐子里的糖豆数量是否大于零,您不需要计算糖果豆的数量。只需要查看是否至少有一个。
此外,除了更高效外,该代码现在读起来就像代码的预期含义。如果您想询问“列表中是否有任何项目?”,请问“列表中是否有任何项目?” 而不是 “列表中的项目数是否大于零?”
列表的 Capacity 属性呢?
它告诉您预先分配在列表的内部数据结构中的空间量。这是列表在必须分配更多内存之前可以存储的项数。

我们在运行时查询序列,以查看它是否是一个具有可高效计算的Count属性的列表。这是什么意思?您是检查名为“Count”的属性,还是检查是否实现了ICollection<T>?如果使用IEnumerable<T>的协变,第二种情况会有一些有趣的特殊情况。 - CodesInChaos
1
@CodeInChaos:通过反射查找名为Count的属性既慢又不可靠。我们寻找接口的实现。是的,由于协变问题,你可能会得到错误的结果。如果这样做会让你感到痛苦,那就不要这样做。 - Eric Lippert
2
@CodeInChaos 如果对 ICollection<T> 的检查失败,那么代码会检查非泛型的 ICollection。因此,大多数框架集合都不会受到协变问题的影响。 - phoog

6
在BCL中,List<T>Count属性以及所有其他ICollection<T>实现都是O(1)操作,这意味着它快速且与列表中元素数量无关。此外,还存在一个扩展方法Count(),可在任何IEnumerable<T>上调用。该方法是O(n),这意味着其运行时取决于可枚举对象中元素的数量。但是,有一个例外:如果可枚举对象确实是ICollection<T>ICollection的实现,则使用Count属性,使其再次成为O(1)操作。
通常情况下,Capacity属性不是您需要担心的问题。

2
好的,考虑到 OP 在列表中提到了 986,000 个元素,恰当地管理容量 可能 带来显著的好处。 - Tigran
每次命中时,容量都会加倍,因此仅在填充大量列表时管理容量才会带来真正的好处。 - Daniel Hilgarth
这就是我的意思:在某些情况下(例如CAD程序),它可以带来好处。 - Tigran
我认为这是正确的。上次我读到这方面的内容已经很多年了,我不认为有什么改变。 - Tigran
@Tigran:是的,我也认为这是正确的 - MSDN中的示例也支持它。我只是有点糊涂,已经删除了那条评论 :-) - Daniel Hilgarth

2

在列表中,计数是O(1)操作,这是最快的方式。

计数:实际上列表中存在的元素数量。

容量:更好的文档说明:

获取或设置内部数据结构可以容纳的元素总数而不需要调整大小。


2

请使用以下代码:list.Any()。它可能比List<>.Count慢,但对于大多数IEnumerable<>,它都是最有效的。

Capacity可以大于Count。当您计划稍后添加大量项目时,可以使用它。

List.Count的实现如下(实际上是O(1)):

public int Count
{
  get
  {
    return this._size; // this is a field
  }
}

2
иҷҪ然дҪҝз”Ё.Any()жҜ”дҪҝз”Ё.Count() > 0жӣҙеҘҪпјҢдҪҶе®ғзҡ„ж•ҲзҺҮз•ҘдҪҺпјҢеӣ дёәе®ғдјҡеңЁйӣҶеҗҲдёҠеҲӣе»әдёҖдёӘжһҡдёҫеҷЁгҖӮ - Gabe
对于存储c的列表或任何集合 - the_joric

1

容量并不告诉您列表中有多少个对象 - 只是列表准备好了多少。

来自 MSDN:

Capacity is the number of elements that the List<T> can store before resizing is required, while Count is the number of elements that are actually in the List<T>.

List.Count是超级快的,它是一个被访问的属性,而List.Count()来自IEnumerable,我相信它必须通过列表进行完整枚举。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接