C# IEnumerable.Count()或ToList().Count

C# IEnumerable.Count()或ToList().Count,c#,performance,linq,C#,Performance,Linq,我得到了我自己类的对象列表,看起来像: public class IFFundTypeFilter_ib { public string FundKey { get; set; } public string FundValue { get; set; } public bool IsDisabled { get; set; } } 属性IsDisabled是通过执行查询收集。其中(某些条件)并计算匹配对象的数量来设置的。结果是不包含属性计数的IEnumarable。我

我得到了我自己类的对象列表,看起来像:

public class IFFundTypeFilter_ib
{
    public string FundKey { get; set; }
    public string FundValue { get; set; }
    public bool IsDisabled { get; set; }
}
属性
IsDisabled
是通过执行查询
收集。其中(某些条件)
并计算匹配对象的数量来设置的。结果是不包含属性计数的
IEnumarable
。我想知道,什么会更快

这个:

collection.Where(somecondition).Count();
或者这个:

collection.Where(someocondition).ToList().Count;

集合可以包含很少的对象,但也可以包含,例如700。我要打两次计数电话,还有其他条件。在第一种情况下,我检查FundKey是否等于某个键,在第二种情况下,我也会这样做,但我会将它与其他键值进行比较。

一般来说,具体化到列表的效率会更低

此外,如果您使用两个条件,那么缓存结果或将查询具体化到
列表
是没有意义的

您应该只使用
Count
重载,它接受一个谓词:

collection.Count(someocondition);

正如@CodeCaster在评论中提到的,它相当于collection.Where(condition).Count(),但更具可读性和简洁性。

正是这样使用它的

var count = collection.Where(somecondition).ToList().Count;
没有意义-填充列表只是为了获得计数,因此使用
IEnumerable.count()
是适合这种情况的方法

在您这样做的情况下,使用
ToList
是有意义的

var list = collection.Where(somecondition).ToList();
var count = list.Count;
// do something else with the list
你问:

我想知道,什么会更快

无论何时你要求你实际计时并找出答案

我开始测试所有这些获得计数的变体:

var enumerable = Enumerable.Range(0, 1000000);
var list = enumerable.ToList();

var methods = new Func<int>[]
{
    () => list.Count,
    () => enumerable.Count(),
    () => list.Count(),
    () => enumerable.ToList().Count(),
    () => list.ToList().Count(),
    () => enumerable.Select(x => x).Count(),
    () => list.Select(x => x).Count(),
    () => enumerable.Select(x => x).ToList().Count(),
    () => list.Select(x => x).ToList().Count(),
    () => enumerable.Where(x => x % 2 == 0).Count(),
    () => list.Where(x => x % 2 == 0).Count(),
    () => enumerable.Where(x => x % 2 == 0).ToList().Count(),
    () => list.Where(x => x % 2 == 0).ToList().Count(),
};
以下是结果(从最慢到最快排列):

这里有两件事很重要

第一,任何带有
.ToList()
内联的方法都比没有内联的方法慢得多

第二,LINQ运算符尽可能利用可枚举的基本类型来简化计算。
enumerable.Count()
list.Count()
方法显示了这一点

list.Count
list.Count()
调用之间没有区别。因此,关键的比较是
可枚举.Where(x=>x%2==0.Count()
可枚举.Where(x=>x%2==0.ToList().Count()
调用之间的比较。由于后者包含一个额外的操作,我们预计需要更长的时间。它几乎要长2.5毫秒


我不知道你为什么说你要调用计数代码两次,但如果你这样做了,最好建立一个列表。如果不是这样的话,在查询后只需调用普通的
.Count()

这完全取决于
集合的实际内容。您也可以不数两次,而是存储该数字。我不能,因为在第二次呼叫时,我会检查其他条件。@CodeCaster什么类型的集合在这里并不重要。我猜您忽略了所讨论的where条件。
where
生成惰性枚举,而不管源集合的类型如何
ToList
在这种情况下,必须遍历该可枚举项。比较这些线路,第二条线路要慢一些。但我不清楚OP所说的“我将进行两次计数呼叫”是什么意思,尤其是“我不能,因为在第二次呼叫时,我将检查其他条件”@PawełMikołajczyk:你能发帖吗,你到底要做什么?好吧,当你数口袋里的美元钞票时,什么更快?A:一个接一个地数一数,B:买一个新钱包,把每张账单都复印一张照片,放进新钱包里,然后数一数?
其中(x)。count()
count(x)
@CodeCaster水上发生的事情也很重要:)@CodeCaster我的意思是,虽然这些陈述在性能上是等价的,后者更具可读性和简洁性。我不同意@CodeCaster。它们在性能上也不相同(否则为什么要提供重载)
其中(x)。Count()涉及创建和链接2个枚举数,而
Count(x)
只需要一个。@CodeCaster完全同意
IQueryable
,部分同意
IEnumerable
和微优化-有些人甚至抱怨为什么
IEnumerator
需要两个虚拟调用(
MoveNext
Current
)来实现目标:-),我看不出为
Count
LongCount
any
提供所有这些谓词重载的任何其他原因。平均时间是以秒或毫秒排序的?谢谢。它是
sw.eassed.totalmillizes
var measurements =
    methods
        .Select((m, i) => i)
        .ToDictionary(i => i, i => new List<double>());

for (var run = 0; run < 1000; run++)
{
    for (var i = 0; i < methods.Length; i++)
    {
        var sw = Stopwatch.StartNew();
        var gccc0 = GC.CollectionCount(0);
        var r = methods[i]();
        var gccc1 = GC.CollectionCount(0);
        sw.Stop();
        if (gccc1 == gccc0)
        {
            measurements[i].Add(sw.Elapsed.TotalMilliseconds);
        }
    }
}

var results =
    measurements
        .Select(x => new
        {
            index = x.Key,
            count = x.Value.Count(),
            average = x.Value.Average().ToString("0.000")
        });
+---------+-----------------------------------------------------------+
| average |                          method                           |
+---------+-----------------------------------------------------------+
| 14.879  | () => enumerable.Select(x => x).ToList().Count(),         |
| 14.188  | () => list.Select(x => x).ToList().Count(),               |
| 10.849  | () => enumerable.Where(x => x % 2 == 0).ToList().Count(), |
| 10.080  | () => enumerable.ToList().Count(),                        |
| 9.562   | () => enumerable.Select(x => x).Count(),                  |
| 8.799   | () => list.Where(x => x % 2 == 0).ToList().Count(),       |
| 8.350   | () => enumerable.Where(x => x % 2 == 0).Count(),          |
| 8.046   | () => list.Select(x => x).Count(),                        |
| 5.910   | () => list.Where(x => x % 2 == 0).Count(),                |
| 4.085   | () => enumerable.Count(),                                 |
| 1.133   | () => list.ToList().Count(),                              |
| 0.000   | () => list.Count,                                         |
| 0.000   | () => list.Count(),                                       |
+---------+-----------------------------------------------------------+