我有一个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内部,将countmax打印到调试输出。 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();


但是,由于以后仅在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);

关于c# - 子句比项目计数更频繁地调用,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22884250/

10-10 22:14