NewTom
NewTom

Reputation: 159

Linq MaxBy with all elements?

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?

Upvotes: 6

Views: 11011

Answers (3)

MikeJ
MikeJ

Reputation: 1379

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})");
    }

Upvotes: 1

Ran Turner
Ran Turner

Reputation: 18116

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);

Upvotes: 8

Theodor Zoulias
Theodor Zoulias

Reputation: 43812

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.

Upvotes: 1

Related Questions