然后按顺序计数并选择按组分组,性能问题

时间:2017-01-30 10:06:18

标签: c# .net linq

我尝试按列表分组,然后计算每个组中的项目,然后根据其计数仅选择每个组的最大值。以下代码可以正常工作并完成我的需要。问题是它非常慢,尤其是第二步。您是否知道以更有效的方式实现相同结果的方法?

var grouppedList = sourceList.Where(j => j.field1 == "1000")
    .GroupBy(i => new { mask = i.field2.Substring(0, 1), f3 = i.field3, f4 = i.field4 })
    .Select(k => new
    {
        f4 = k.Key.f4,
        mask = k.Key.mask,
        f3 = k.Key.f3,
        Total = k.Count()
    });

var totalsList = grouppedList
    .Where(i => !grouppedList.Any(j => 
                       j.mask == i.mask && j.f4 == i.f4 && j.Total > i.Total))
    .ToList();

2 个答案:

答案 0 :(得分:2)

您的groupedList不是List。这是IEnumerable。所以每次访问它时都会执行它。然后你为它的每一部分访问它(在Where子句中)。我建议从它创建一个列表(只执行一次查询):

var grouppedList = sourceList.Where(j => j.field1 == "1000")
    .GroupBy(i => new { mask = i.field2.Substring(0, 1), f3 = i.field3, f4 = i.field4 })
    .Select(k => new
    {
        f4 = k.Key.f4,
        mask = k.Key.mask,
        f3 = k.Key.f3,
        Total = k.Count()
    }).ToList();

另一种可能性是将分组和获取项目与最多Total相结合,我会这样做:

var grouppedList = sourceList.Where(j => j.field1 == "1000")
.GroupBy(i => new { mask = i.field2.Substring(0, 1), f3 = i.field3, f4 = i.field4 })
.Select(k => new
{
    f4 = k.Key.f4,
    mask = k.Key.mask,
    f3 = k.Key.f3,
    Total = k.Count()
})
.GroupBy(x => new {x.mask, x.f4})
.Select(x=>x.OrderBydescending(t=>t.Total).First());
.ToList();

答案 1 :(得分:1)

这段代码看起来很慢的原因可能就是你要两次迭代grouppedList

var totalsList = grouppedList.Where(i => !grouppedList.Any(
    j => j.mask == i.mask && j.f4 == i.f4 && j.Total > i.Total)
).ToList();

将对groppedList中所有元素的内部Where - 语句中的groppuedList进行迭代。您可以考虑使用ToList强制立即执行例如:

var grouppedList = sourceList.Where(j => j.field1 == "1000")
.GroupBy(i => new { mask = i.field2.Substring(0, 1), f3 = i.field3, f4 = i.field4 })
.Select(k => new
{
    f4 = k.Key.f4,
    mask = k.Key.mask,
    f3 = k.Key.f3,
    Total = k.Count()
}).Tolist();    // this forces an immediate execution of your select-statement

现在打电话给你的第二个陈述

var totalsList = grouppedList.Where(i => !grouppedList.Any(j => j.mask == i.mask && j.f4 == i.f4 && j.Total > i.Total)).ToList();

它将使用allready物化列表,而不是一次又一次地执行查询。