同等の 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 クエリを作成するにはどうすればよいですか?
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
minとmaxの両方(およびそこにスローしたい他の集計)を生成する単一の列挙。これは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 で複数の集計を効率的に選択することはできません。もちろん、複数のクエリを実行できますが、データ ソースによっては効率が悪い場合があります。
私は「Push LINQ」と呼んでいるこれに対処するフレームワークを持っています。これは単なる趣味です (私と Marc Gravell にとって) ですが、かなりうまく機能すると信じています。これはMiscUtilの一部として利用でき、それについては私のブログ投稿で読むことができます。
少し奇妙に見えます-結果をどこに送るかを「先物」として定義し、クエリを介してデータをプッシュしてから結果を取得するためです-しかし、頭が丸くなったら問題ありません。あなたがそれをどのように使いこなしているかを知りたいです - もしあなたがそれを使っているなら、skeet@pobox.com まで私にメールしてください。
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;
}