2008-09-30 97 views
6

我將如何創建等效的Linq To Objects查詢?LINQ查詢與多個聚合

SELECT MIN(CASE WHEN p.type = "In" THEN p.PunchTime ELSE NULL END) AS EarliestIn, 
     MAX(CASE WHEN p.type = "Out" THEN p.PunchTime ELSE NULL END) AS LatestOUt 
FROM Punches p 

回答

2

你不能在vanilla LINQ to Objects中有效地選擇多個聚合。當然,您可以執行多個查詢,但根據您的數據源,這可能效率很低。

我有一個框架,對付這個我稱之爲「推LINQ」 - 這只是一個業餘愛好(對於我和Marc Gravell),但我們相信它工作得很好。它作爲MiscUtil的一部分提供,您可以在my blog post on it中閱讀。

它看起來有點奇怪 - 因爲您定義了希望結果作爲「期貨」的位置,然後通過查詢推送數據,然後檢索結果 - 但是一旦您將頭轉過來,就沒有問題。我很想聽聽你如何繼續使用它 - 如果你使用它,請發郵件到[email protected]

+0

謝謝Jon。到目前爲止,Linq最困難的部分之一就是搞清楚你能做什麼,不能做什麼。一旦我對標準方法更加適應,我一定會看看你的Push技術。 – 2008-09-30 20:07:07

4

單枚枚舉產生最小值和最大值(以及任何其他想要拋入的聚合)。這在vb.net中更容易。

我知道這不處理空案。這很容易添加。

List<int> myInts = new List<int>() { 1, 4, 2, 0, 3 }; 
    var y = myInts.Aggregate(
     new { Min = int.MaxValue, Max = int.MinValue }, 
     (a, i) => 
     new 
     { 
      Min = (i < a.Min) ? i : a.Min, 
      Max = (a.Max < i) ? i : a.Max 
     }); 
    Console.WriteLine("{0} {1}", y.Min, y.Max); 
+0

這是一個手冊,但它對我來說已經足夠了。當你打斷linq時,你很快就會回到僅僅是foreach外觀的語法快捷方式。 – 2008-09-30 21:54:23

0

可以使用LINQ到對象進行多個聚合,但它有點難看。

var times = punches.Aggregate(
    new { EarliestIn = default(DateTime?), LatestOut = default(DateTime?) }, 
    (agg, p) => new { 
     EarliestIn = Min(
      agg.EarliestIn, 
      p.type == "In" ? (DateTime?)p.PunchTime : default(DateTime?)), 
     LatestOut = Max(
      agg.LatestOut, 
      p.type == "Out" ? (DateTime?)p.PunchTime : default(DateTime?)) 
    } 
); 

您還需要DateTime的Min和Max函數,因爲這些函數是不可用的標準。

public static DateTime? Max(DateTime? d1, DateTime? d2) 
{ 
    if (!d1.HasValue) 
     return d2; 
    if (!d2.HasValue) 
     return d1; 
    return d1.Value > d2.Value ? d1 : d2; 
} 
public static DateTime? Min(DateTime? d1, DateTime? d2) 
{ 
    if (!d1.HasValue) 
     return d2; 
    if (!d2.HasValue) 
     return d1; 
    return d1.Value < d2.Value ? d1 : d2; 
}