Получить Max и Min в одном запросе LINQ

У меня есть набор объектов с двумя свойствами, A и B. Я хотел бы получить минимум A и максимум B.

например

var minA = objects.Min(o => o.A);
var maxB = objects.Max(o => o.B);

используя синтаксис запроса LINQ, есть ли способ сделать это, чтобы он только один раз прошел через набор?

желаемым результатом будет анонимный тип (например, результаты.MinA = x, результаты.MaxB = y)

5 ответов


Min и Max являются агрегатами. Общая агрегатная функция linq -совокупность

предполагая, что свойство A-целое число, А B-строка, вы можете написать что-то вроде этого:

objects.Aggregate(
    new {
        MinA = int.MaxValue,
        MaxB = string.Empty
    },
    (accumulator, o) => new {
        MinA = Math.Min(o.A, accumulator.MinA),
        MaxB = o.B > accumulator.MaxB ? o.B : accumulator.MaxB
    });

Я знаю, что вы хотели запрос Linq, но я не могу перестать указывать, что версия без linq может быть намного больше читабельный. Сравните это:

IEnumerable<Message> messages = SomeMessages();

Func<DateTime, DateTime, DateTime> min = (dt1, dt2) => dt1 > dt2 ? dt2 : dt1;
Func<DateTime, DateTime, DateTime> max = (dt1, dt2) => dt1 > dt2 ? dt1 : dt2;

// linq version
var result = messages.Aggregate(
    new { StartDate = DateTime.MaxValue, EndDate = DateTime.MinValue }, /* initial value */
    (accumulate, current) => new { StartDate = min(accumulate.StartDate, current.ReceivedTime), EndDate = max(accumulate.EndDate, current.ReceivedTime) });

// non-linq version
DateTime start = DateTime.MaxValue;
DateTime end = DateTime.MinValue;
foreach (DateTime dt in messages.Select(msg => msg.ReceivedTime))
{
    start = min(start, dt);
    end = max(end, dt);
}

можно использовать Aggregate метод.

var res = new { Min = objects[0].A, Max = objects[0].B }
var res = objects.Aggregate(res, (r, curr) => r.Min = r.Min < curr.A ? r.Min : curr.A; r.Max = r.Max > curr.B ? r.Max : curr.B);

можно использовать YourObject в качестве контейнера для результатов, и использовать Math.Min и Math.Max привести в порядок синтаксис:

var maxmin = objects.Aggregate(objects[0], (i, j) =>
            new YourObject { A = Math.Min(i.A, j.A), B = Math.Max(i.B, j.B) });

что-то вроде этого будет работать для вас Мой предыдущий ответ не сработал,

Я вернулся и попробовал несколько разных ответов здесь и закончил с этим решением, предложенным ранее

        var values = new List<int> {1, 2, 3, 4, 5};

        var maxmin = new {min = values.Min(), max = values.Max()};