我有一个List<Order>
,我试图使用LINQ过滤这个:
var grouped = from o in orders
group o by o.OrderNumber into g
select new { Id = g.Key, Orders = g };
var GroupedList = grouped.ToList();
int max = GroupedList.Count();
int count = 0;
var filtered =
from g in GroupedList
where IncrementProgress(max, ref count)
select g.Id;
var filteredOrders = orders.Where(o => filtered.Contains(o.OrderNumber));
在IncrementProgress
内我打印count
和max
到调试输出。 max
在我的测试3500中,我从1500 count
获得输出并计数。
有人知道为什么吗?
PS:在我的生产代码中,有过滤逻辑而不是IncrementProgress
。
更新
这里是IncrementProgress
- 方法:
private bool IncrementProgress(int max, ref int count)
{
Debug.WriteLine("Filtering {0} of {1}", ++count, max);
return true;
}
答案 0 :(得分:2)
每次枚举过滤后的集合时都会执行LINQ
查询,在每次调用Contains方法的情况下都会执行。
尝试将过滤后的变量声明为(<LINQ Query>).ToArray()
。
这将只查询一次查询。
抱歉格式不佳(手机)。 希望它有所帮助。
答案 1 :(得分:2)
那是因为LINQ是惰性的而filtered
不是集合 - 它是一个内存中的查询,它只存储如何评估结果的信息,而不是结果本身。因此,每次使用filtered
时,都会再次对其进行评估,重复GroupedList
并再次检查where
条件。
这意味着,where
条件将被评估orders.Count() * GroupedList.Count()
次。
向ToList()
添加filtered
来急切地评估它。
var filtered =
(from g in GroupedList
where IncrementProgress(max, ref count)
select g.Id).ToList();
但是,由于您之后仅在Contains
上使用filtered
,因此您应使用HashSet<int>
来存储结果。这将使Contains
调用 O(1)而不是 O(n),这将大大提高性能。
var filtered =
new HashSet<int>(from g in GroupedList
where IncrementProgress(max, ref count)
select g.Id);