我有一个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 中,我从 150000 的 count
中获得输出并且还在不断增加。
有人知道为什么吗?
PS:在我的生产代码中,有过滤器逻辑而不是IncrementProgress
。
更新:
这里是IncrementProgress
-方法:
private bool IncrementProgress(int max, ref int count)
{
Debug.WriteLine("Filtering {0} of {1}", ++count, max);
return true;
}
这是因为 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();
但是,由于您稍后仅在filtered
上使用Contains
,因此应使用HashSet<int>
来存储结果。它将使Contains
调用 O(1) 而不是 O(n),这应该会大大提高性能。
var filtered =
new HashSet<int>(from g in GroupedList
where IncrementProgress(max, ref count)
select g.Id);
枚举筛选的集合时都会执行LINQ
查询,在每次调用 Include 方法时都会执行。
尝试将过滤后的变量声明为 (<LINQ Query>).ToArray()
。这将仅枚举查询一次。
抱歉格式不正确(手机)。希望对您有所帮助。