Home > Software engineering >  Linq MaxBy with all elements?
Linq MaxBy with all elements?

Time:11-07

I would like to get ALL elements in enumerable whose property is the maximum :

IEnumerable<Person> allOldest = people.GroupBy(p => p.Age)
    .OrderByDescending(i=>i.Key).First().Select(_=>_);

.NET 6 introduce MaxBy which return THE max item:

Person uniqueOldest = people.MaxBy(person => person.Age);

MaxBy can't help me ? Is there another more elegant solution than first example?

CodePudding user response:

Using Max is a simple plain way of doing this:

var maxAge = items.Max(y => y.Age);
var maxItems = items.Where(x => x.Age == maxAge);

CodePudding user response:

If you are OK with adding an external dependency to your project, you could install the respectable MoreLinq package (originally developed by the one and only Jon Skeet) and do this:

IEnumerable<Person> allOldest = MoreLinq.MoreEnumerable.MaxBy(people, p => p.Age);

The signature of the MoreEnumerable.MaxBy method:

public static IExtremaEnumerable<TSource> MaxBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> selector);

You could also try to use it as an extension method, by adding this using directive at the top:

using static MoreLinq.Extensions.MaxByExtension;

...but in .NET 6 this will result (most likely) in a name resolution conflict.

CodePudding user response:

This is one of those times that linq isn't necessarily the best option. You could create a linq style extension to do it but really the most direct solution is just to write a function. Here's a simple example. I've used a value tuple as a stand in for your person object.

    static void Main(string[] _)
    {
        var source = new (int key, int value)[] { (0, 0), (1, 5), (2, 1), (3, 5), (4, 0), (5, 5) };

        var allMax = new List<(int, int)>();
        int currentMax = int.MinValue;

        foreach (var (key, value) in source)
        {
            if (currentMax < value)
            {
                allMax.Clear();
                allMax.Add((key, value));
                currentMax = value;
            }
            else if (currentMax == value)
            {
                allMax.Add((key, value));
            }
        }

        Console.WriteLine($"{allMax.Count} Max valued items found");

        foreach (var (key, value) in allMax)
            Console.WriteLine($"({key}, {value})");
    }
  • Related