Get Max and Min in a single LINQ query
There are new helpers for LINQ in .NET 6 for this matter: MaxBy and MinBy
var people = GetPeople();
var oldest = people.MaxBy(p => p.Age);
var youngest = people.MinBy(p => p.Age);
Console.WriteLine($"The oldest person is {oldest.Age}");
Console.WriteLine($"The youngest person is {youngest.Age}");
Min and Max are both aggregates. The general linq aggregate function is Aggregate
Assuming property A is an integer, and B is a string, you could write something like this:
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
});
I know you wanted a Linq query, but I can't stop pointing out the non-linq version may be much more readable. Compare this:
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);
}
You can use Aggregate
method.
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);