在不进行迭代的情况下,如何计算 IEnumerable 中的项数?
问题的出现原因:
问题的出现是因为在对一个`IEnumerable
解决方法:
有几种解决方法可以避免在迭代时计数集合中的元素:
1. 使用`Count()`扩展方法:`Count()`扩展方法并不总是进行迭代。例如,在Linq to Sql中,计数是通过向数据库发出`Count()`命令并返回结果来实现的,而不是将所有行都带回来。此外,编译器(或运行时)足够聪明,如果对象有`Count()`方法,它会直接调用该方法。因此,`Count()`方法并不是像其他回答者所说的完全无知地进行迭代来计数元素。
2. 使用`Any()`扩展方法:在许多情况下,如果程序员只是想检查`IEnumerable
3. 对于集合和数组,可以直接使用`Count`属性或`Array.Length`属性来获取元素的数量。对于集合来说,`Count`属性总是知道集合的大小,查询`collection.Count`不需要任何额外的计算,只需返回已知的计数即可。对于数组来说,`Array.Length`属性也是同样的道理。对于枚举器,可以使用`Any()`方法来判断是否有元素存在。
需要注意的是,第一个观点并不完全正确。LINQ to SQL使用的是不同于上述提到的两个扩展方法。如果使用第二个扩展方法,计数将在内存中执行,而不是作为SQL函数执行。另外,如果将`IQueryable
在使用C#编程时,有时候我们需要统计一个IEnumerable
如果我们想要在不遍历元素的情况下知道元素的数量,可以使用ICollection
如果不需要通过索引访问列表,我更倾向于使用ICollection而不是IList。
通常情况下,我习惯于使用List和IList。但是特别是在需要自己实现列表时,使用ICollection更简单,而且也有Count属性。
那么当我们有一个给定的IEnumerable时,如何检查其元素的数量呢?你可以遍历并计数元素,或者调用Linq命名空间中的Count()方法来实现。
在正常情况下,简单地将IEnumerable替换为IList是否足够呢?由于IEnumerable的惰性求值特性,它可以用于IList无法使用的场景。比如,你可以构建一个返回IEnumerable的函数,用于枚举圆周率的所有小数位数。只要你不尝试完整地foreach整个结果,它应该可以正常工作。而你无法创建一个包含圆周率的IList。但是这些都是理论上的问题,对于大多数正常的使用场景,我完全同意。如果你需要获取元素数量,你需要IList。
明白了,谢谢。我将我的IEnumerable转换为了IList,没有任何问题!
那么如果你不知道传入的列表的类型(字典、列表等),你想要你的方法更灵活,允许调用者指定类型。但是你仍然需要遍历这个传入的列表或字典怎么办?我猜你可以在方法内部检查传入的类型,然后执行相应的操作。
如果你需要一个字典怎么办?
没有使用IEnumerable是没有问题的,我通常在方法签名中使用这个类型,以增加灵活性,就像你说的那样。但是如果你真的需要在不遍历元素的情况下获取集合的元素数量,那么使用IList(或者正如Michael Meadows所建议的更好的ICollection)是正确的方法。如果我没有记错的话,IDictionary也是从IList继承而来的,作为键值对的列表。
非泛型的ICollection的一个优点是,它可以在不知道泛型集合的实际元素类型的情况下使用。例如,假设一个接受IEnumerable
要处理不同类型的集合并且高效地编写方法,有时候需要编写多个版本的方法。这违反了DRY原则,但在C#中,如果count对性能有帮助,这是不可避免的权衡考虑。如果要处理的集合是List,则可以使用abc
通过使用ICollection或IList接口,我们可以在不遍历元素的情况下获取IEnumerable
在使用IEnumerable
这种实现方式很有趣,大多数Enumerable中的扩展方法都对各种类型的序列进行了优化,如果可能的话,它们会使用更便宜的方法。
在.NET 3.5中引入了这个扩展方法,并在MSDN中有文档记录。
有人认为在IEnumerator
另外,这也取决于你对结果的处理。通常情况下,你希望类型
遗憾的是,.NET没有介于IEnumerable和ICollection之间的中间接口,用于具有已知数量的IEnumerable(但不需要ICollection的其他特性)。也没有办法知道,对于任意的IEnumerable和在算法中需要提前知道“Count”的情况,调用IEnumerable.Count会迭代两次的性能是否更好,还是先收集到一个列表中,然后使用列表的Count。更糟糕的是,迭代可能会有“副作用”。另一方面,枚举可能有很多元素。
另一种语法是(enumerator as IDisposable)?.Dispose()。
需要注意的是,实现IDisposable接口的是IEnumerator
所以,结论是"所以你最好使用Count()扩展方法来获得最佳的性能",只有当你使用的类型实现了ICollection