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

时间:2011-10-05 15:47:01

标签: 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
                    }

                }

在哪里过滤一个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
                    }

                }

TIA。

1 个答案:

答案 0 :(得分: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 

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

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


*对于间接层,可能存在测量惩罚,如果您认为它是真正的瓶颈,则必须对此进行分析。但请将Count()方法视为

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