IEnumerable.Count() or ToList().Count
我得到了我自己类的对象列表,如下所示:
1 2 3 4 5 6 | public class IFFundTypeFilter_ib { public string FundKey { get; set; } public string FundValue { get; set; } public bool IsDisabled { get; set; } } |
属性
这一个:
1 | collection.Where(somecondition).Count(); |
或者这个:
1 | collection.Where(someocondition).ToList().Count; |
集合可以包含很少的对象,但也可以包含,例如700。我要打两次计数电话,还有其他条件。在第一个条件中,我检查fundkey是否等于某个键,在第二个条件中,我也这样做,但我将它与其他键值进行比较。
你问:
I wonder, what would be faster.
每当你问你应该实际计时并找出答案。
我开始测试获得计数的所有变量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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(), }; |
我的测试代码显式地运行每个方法1000次,使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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") }); |
以下是结果(顺序从最慢到最快):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | +---------+-----------------------------------------------------------+ | 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(), | +---------+-----------------------------------------------------------+ |
这里有两件事很重要。
第一,任何一种方法,如果使用
第二,LINQ运算符利用可枚举的基础类型(如果可能)来简化计算。
我不知道你为什么说你要两次调用计数代码,但如果你这样做,最好是建立列表。如果不只是在查询后执行普通的
一般来说,具体化到列表中的效率会降低。
另外,如果您使用两个条件,那么就没有必要缓存结果或将查询具体化到
您应该只使用接受谓词的
1 | collection.Count(someocondition); |
正如@codecaster在评论中提到的,它相当于
就是这样用的
1 | var count = collection.Where(somecondition).ToList().Count; |
没有意义-填充一个列表只是为了得到计数,所以使用
在这种情况下,使用
1 2 3 | var list = collection.Where(somecondition).ToList(); var count = list.Count; // do something else with the list |