linq IEnumerable.Count()或ToList().Count函数中的一个

vwoqyblh  于 2022-12-06  发布在  其他
关注(0)|答案(4)|浏览(136)

我得到了我自己的类的对象列表,如下所示:

public class IFFundTypeFilter_ib
{
    public string FundKey { get; set; }
    public string FundValue { get; set; }
    public bool IsDisabled { get; set; }
}

属性IsDisabled是通过查询collection.Where(some condition)并计算匹配对象的数量来设置的。结果是IEnumarable<IFFundTypeFilter_ib>,它不包含属性Count。我想知道,什么会更快。
这一条:

collection.Where(somecondition).Count();

或者是这个:

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

集合可以包含几个对象,但也可以包含,例如700。我将进行两次计数调用,并使用其他条件。在第一个条件中,我检查FundKey是否等于某个键,在第二个条件中,我做同样的事情,但我将其与其他键值进行比较。

azpvetkf

azpvetkf1#

你问:
我在想,什么会更快。
无论何时你问,你应该实际上计时,并找出。
我开始测试获得计数的所有这些变体:

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(),
};

我的测试代码显式地运行每个方法1,000次,用Stopwatch测量每个执行时间,并忽略所有发生垃圾收集的结果,然后得到每个方法的平均执行时间。

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(),                                       |
+---------+-----------------------------------------------------------+

这里有两件事很重要。
第一,任何带有.ToList()内联函数的方法都比不带它的方法慢得多。
第二,LINQ操作符利用可枚举对象的底层类型,在可能的情况下,简化计算。enumerable.Count()list.Count()方法说明了这一点。
list.Countlist.Count()调用之间没有区别,所以关键的比较是enumerable.Where(x => x % 2 == 0).Count()enumerable.Where(x => x % 2 == 0).ToList().Count()调用之间的比较,因为后者包含了一个额外的操作,我们预计它会花费更长的时间,几乎长了2.5毫秒。
我不知道你为什么说你要调用计数代码两次,但是如果你这样做的话,最好还是构建列表。如果不是这样,就在你的查询之后执行普通的.Count()调用。

7lrncoxx

7lrncoxx2#

一般来说,具体化到列表的效率较低。
此外,如果使用两个条件,则缓存结果或将查询具体化为List是没有意义的。
您应该只使用接受 predicate 的Count重载:

collection.Count(someocondition);

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

uqxowvwt

uqxowvwt3#

就这样使用

var count = collection.Where(somecondition).ToList().Count;

没有意义--仅仅为了获得计数而填充列表,因此使用IEnumerable<T>.Count()是这种情况的适当方法。
在这样的情况下,使用ToList是有意义的

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

g6ll5ycj4#

没有ToList()的纯Count()背后的SQL非常直接,不会强制任何填充列表所必需的数据传输。

相关问题