1

考虑一个函数 (GetData),它返回以下结果集,其中第一列是部门 id,第二列是“TotalSales”:

DivisionID: 3     500
DivisionID: 3     500
DivisionID: 3     500

DivisionID: 4     800     
DivisionID: 4     800

DivisionID: 5     50

我需要编写一个 LINQ 查询来获得以下结果:

DiviosnID 3: (500 * 3) - 500 = 1000
DiviosnID 4: (800 * 2) - 800 = 800
DiviosnID 5: 0 /*this since it's happening only once*/

所以总数变为:1000 + 800 = 1800

最后,这个值应该乘以 -1,结果是 -1800。

以下 LINQ 查询完成了工作,但是恕我直言,这很可怕。问题是它是否可以重新编写以更快地执行并看起来更好?!请注意那里有第三列,就像我需要对其进行相同计算的名为“TotalPurchases”的 TotalSales。

GetData()
.Where(t => t.DivisionId != 0)
.GroupBy(t => t.DivisionId)
.Where(g => g.Count() > 1)
.Select(g => new MyEntity
{
    TotalSales = g.Sum(n => n.TotalSales) - (g.Sum(n => n.TotalSales) / g.Count()),
    TotalPurchases = g.Sum(n => n.TotalPurchases) - (g.Sum(n => n.TotalPurchases) / g.Count())
})
.Union(Enumerable.Repeat(new MyEntity(), 1))
.Aggregate((t1, t2) => new MyEntity
{
    TotalSales = -(t1.TotalSales + t2.TotalSales),
    TotalPurchases = -(t1.TotalPurchases + t2.TotalPurchases),
});

谢谢

4

2 回答 2

0

快速的第一次尝试:

var consolidatedData = GetData()
        .GroupBy(t => t.DivisionId)
        .Where(g => g.Skip(1).Any(i => i.DivisionId != 0))
        .Select(g => new
        {
            TotalSales = -(g.Sum(n => n.TotalSales) - g.Average(n => n.TotalSales)),
            TotalPurchases = -(g.Sum(n => n.TotalPurchases) - g.Average(n => n.TotalPurchases))
        });

var overallSales = consolidatedData.Sum(i => i.TotalSales);
var overallPurchases = consolidatedData.Sum(i => i.TotalPurchases);

使用 Skip,您可以避免在每个组上运行可能很昂贵的 Count() - 它只是跳过一个项目,并查看是否还有任何剩余。

通过将结果构建到匿名对象的 IEnumerable 中,可以简化代码 - 然后您可以在需要最终总和时查询它。请注意,Average 也用于代替 Sum / Count。

聚合被删除 - 您只在需要时计算最后的总和。

于 2013-10-25T09:21:15.960 回答
0

我的提议:

var result = data
    .Where(t => t.DivisionID != 0)
    .GroupBy(t => t.DivisionID)
    .Select(g => new MyEntity
    {
        TotalSales = g.Sum(n => n.TotalSales) - g.Average(n => n.TotalSales),
        TotalPurchases = g.Sum(n => n.TotalPurchases) - g.Average(n => n.TotalPurchases)
    })
    .Aggregate(new MyEntity(), (t1, t2) => new MyEntity
    {
        TotalSales = t1.TotalSales - t2.TotalSales,
        TotalPurchases = t1.TotalPurchases - t2.TotalPurchases,
    });

Where(g => g.Count() > 1)不需要检查,因为 1 个元素组的 SUM 和 AVG 相等,所以 select 将返回 0。我也删除Union(Enumerable.Repeat(new MyEntity(), 1))并添加seed到聚合调用 - 这是起始值。

另一个:

var result = data
    .Where(t => t.DivisionID != 0)
    .GroupBy(t => t.DivisionID)
    .Select(g => new MyEntity
    {
        TotalSales = g.Sum(n => n.TotalSales) - g.Average(n => n.TotalSales),
        TotalPurchases = g.Sum(n => n.TotalPurchases) - g.Average(n => n.TotalPurchases)
    })
    .GroupBy(t => 0) // create single group
    .Select(g => new MyEntity
    {
        TotalSales = -g.Sum(t => t.TotalSales),
        TotalPurchases = -g.Sum(t => t.TotalPurchases)
    })
    .SingleOrDefault();

假设这TotalSales是恒定的,DivisionId您可以使用它:

var result = data
    .Where(t => t.DivisionID != 0)
    .GroupBy(t => t.DivisionID)
    .Select(g => new MyEntity
    {
        TotalSales = g.Skip(1).Sum(n => n.TotalSales),
        TotalPurchases = g.Skip(1).Sum(n => n.TotalPurchases)
    })
    .Aggregate(new MyEntity(), (t1, t2) => new MyEntity
    {
        TotalSales = t1.TotalSales - t2.TotalSales,
        TotalPurchases = t1.TotalPurchases - t2.TotalPurchases,
    });

var result = data
    .Where(t => t.DivisionID != 0)
    .GroupBy(t => t.DivisionID)
    .Select(g => new MyEntity
    {
        TotalSales = g.Skip(1).Sum(n => n.TotalSales),
        TotalPurchases = g.Skip(1).Sum(n => n.TotalPurchases)
    })
    .GroupBy(t => 0) // create single group
    .Select(g => new MyEntity
    {
        TotalSales = -g.Sum(t => t.TotalSales),
        TotalPurchases = -g.Sum(t => t.TotalPurchases)
    })
    .SingleOrDefault();
于 2013-10-25T09:32:12.043 回答