簡體   English   中英

重構以下LINQ查詢以使其性能更好,看起來更簡單

[英]Refactoring the following LINQ query to perform better and look more simple

考慮一個函數(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查詢可以完成工作,但是,IMSHO令人恐懼。 問題是,是否可以重寫它以更快地執行並看起來更好? 請注意,這里有第三列,就像名為“ 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),
});

謝謝

快速的第一次嘗試:

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);

使用“跳過”,可以避免在每個組上運行潛在昂貴的Count()-它僅跳過一項,然后查看是否還有剩余。

通過將結果構建到一個匿名對象的IEnumerable中,可以簡化代碼-然后,您可以在需要最終總和時查詢它。 請注意,平均值也用於代替總和/計數。

聚合被刪除-僅在需要時才計算最終總和。

我的主張:

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)檢查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();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM