具有多个聚合的LINQ查询
时间:2020-03-06 14:56:37 来源:igfitidea点击:
我将如何创建等效的Linq To Objects查询?
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
解决方案
我们无法在香草LINQ to Objects中有效地选择多个聚合。当然,我们可以执行多个查询,但这可能效率很低,具体取决于数据源。
我有一个可以解决这个问题的框架,我称之为" Push LINQ",这只是一个业余爱好(对我和Marc Gravell而言),但我们认为它可以很好地工作。它是MiscUtil的一部分,我们可以在我的博客文章中阅读有关它的信息。
看起来有些奇怪,因为我们将结果定义为"未来",然后将数据推送到查询中,然后检索结果,但是一旦找到答案,就可以了。如果我们使用它,我很想听听我们如何使用它,请给我发电子邮件[email protected]。
单个枚举同时产生最小值和最大值(以及我们想在其中抛出的任何其他聚合值)。在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);
可以使用LINQ-to-Objects进行多个聚合,但这有点难看。
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; }