LINQ:使用IEnumerable.Count()或IList.Count以获得更好的性能

Kla*_*Nji 4 linq deferred-execution

基于以下代码:

 var grouped = filters.GroupBy(p => p.PropertyName);
                 int numOfRowElements = grouped.Count();
     foreach (IGrouping<string, PropertyFilter> filter in grouped)
                {


                    foreach (var propertyFilter in filter)
                    {
                        // do something
                    }

                }
Run Code Online (Sandbox Code Playgroud)

在过滤List的过程中,我的理解是调用IEnumerable.Count()会强制执行查询.这个执行的结果是存储在分组变量中,然后在foreach循环中使用,或者foreach循环是否强制查询再次执行?这样做会更好吗?

 var grouped = filters.GroupBy(p => p.PropertyName).ToList();
  int numOfRowElements = grouped.Count;
     foreach (IGrouping<string, PropertyFilter> filter in grouped)
                {


                    foreach (var propertyFilter in filter)
                    {
                        // do something
                    }

                }
Run Code Online (Sandbox Code Playgroud)

TIA.

Ant*_*ram 5

如果基础数据源是IList<T>,Enumerable.Count().Count作为优化调用该属性,因此没有*性能损失.如果不是,则强制进行枚举.仔细考虑这一点.

var someList = new List<int>(); 
var count = someList.Count(); // will use .Count property
var count = someList.OrderBy(x => x).Count(); // will force enumeration 
Run Code Online (Sandbox Code Playgroud)

在这个例子中,我只是在第二个语句中得到列表的计数.在第三个,我正在订购列表,然后得到计数.对列表进行排序会返回序列,而不是列表.因此,该Count()方法不是一个IList<T>,而是一个IEnumerable<T>.在这种情况下,必须枚举查询以获取结果,并且将产生与其一起出现的任何成本(在这种情况下,排序).

鉴于此,在您的第一个代码段中,您将枚举您的查询两次.一旦得到计数,一旦在foreach.这将执行两次分组数据的所有逻辑.您的第二个示例将仅执行一次分组操作,同时显然迭代foreach中的结果列表,这应该比第二次执行分组操作更便宜.(您是否可以衡量节省量将完全取决于原始列表中数据的大小和/或来源.如有疑问,请对其进行分析.)


*对于间接层,可能会有一个小的测量惩罚,如果您认为它是一个真正的瓶颈,您将不得不对此进行分析.但是把这个Count()方法想象成

if (sequence is IList<T>) 
{
    return ((IList<T>)sequence).Count
}
else 
{
   /* perform enumeration */;
}
Run Code Online (Sandbox Code Playgroud)