LINQ-запрос с несколькими агрегатами - PullRequest
6 голосов
/ 30 сентября 2008

Как мне создать эквивалентный запрос 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

Ответы [ 3 ]

4 голосов
/ 01 октября 2008

Одиночное перечисление с минимальным и максимальным значением (и любым другим агрегатом, который вы хотите добавить туда). Это намного проще в 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);
2 голосов
/ 30 сентября 2008

Вы не можете эффективно выбрать несколько агрегатов в vanilla LINQ to Objects. Конечно, вы можете выполнять несколько запросов, но это может быть неэффективно в зависимости от вашего источника данных.

У меня есть фреймворк, который справляется с этим, который я называю «Push LINQ» - это всего лишь хобби (для меня и Марка Гравелла), но мы считаем, что он работает довольно хорошо. Он доступен как часть MiscUtil , и вы можете прочитать об этом в моем блоге об этом .

Это выглядит немного странно - потому что вы определяете, куда вы хотите, чтобы результаты отображались как «фьючерсы», затем проталкиваете данные через запрос, затем извлекаете результаты - но как только вы обдумаете это, все будет хорошо. Мне было бы интересно услышать, как вы справляетесь с этим - если вы используете его, пожалуйста, напишите мне по адресу skeet@pobox.com.

0 голосов
/ 19 января 2010

Можно сделать несколько агрегатов с 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?)) 
    }
);

Вам также потребуются функции Min и Max для DateTime, поскольку они не доступны в стандартной комплектации.

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;
}
...