基于以下代码:
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。
答案 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 */;
}