Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to perform .Max() on a property of all objects in a collection and return the object with maximum value [duplicate]

Tags:

c#

object

linq

max

I have a list of objects that have two int properties. The list is the output of another linq query. The object:

public class DimensionPair   {     public int Height { get; set; }     public int Width { get; set; } } 

I want to find and return the object in the list which has the largest Height property value.

I can manage to get the highest value of the Height value but not the object itself.

Can I do this with Linq? How?

like image 756
theringostarrs Avatar asked Jul 09 '09 04:07

theringostarrs


People also ask

How do you find the maximum value in Linq?

In LINQ, you can find the maximum element of the given sequence by using Max() function. This method provides the maximum element of the given set of values. It does not support query syntax in C#, but it supports in VB.NET. It is available in both Enumerable and Queryable classes in C#.

How do I find the maximum number of a list in R?

How to get the max value in a list in R? First, use the unlist() function to convert the list into a vector, and then use the max() function to get the maximum value. The following are the arguments that you can give to the max() function in R. x – The vector for which you want to compute the max value.


2 Answers

We have an extension method to do exactly this in MoreLINQ. You can look at the implementation there, but basically it's a case of iterating through the data, remembering the maximum element we've seen so far and the maximum value it produced under the projection.

In your case you'd do something like:

var item = items.MaxBy(x => x.Height); 

This is better (IMO) than any of the solutions presented here other than Mehrdad's second solution (which is basically the same as MaxBy):

  • It's O(n) unlike the previous accepted answer which finds the maximum value on every iteration (making it O(n^2))
  • The ordering solution is O(n log n)
  • Taking the Max value and then finding the first element with that value is O(n), but iterates over the sequence twice. Where possible, you should use LINQ in a single-pass fashion.
  • It's a lot simpler to read and understand than the aggregate version, and only evaluates the projection once per element
like image 78
Jon Skeet Avatar answered Oct 16 '22 21:10

Jon Skeet


This would require a sort (O(n log n)) but is very simple and flexible. Another advantage is being able to use it with LINQ to SQL:

var maxObject = list.OrderByDescending(item => item.Height).First(); 

Note that this has the advantage of enumerating the list sequence just once. While it might not matter if list is a List<T> that doesn't change in the meantime, it could matter for arbitrary IEnumerable<T> objects. Nothing guarantees that the sequence doesn't change in different enumerations so methods that are doing it multiple times can be dangerous (and inefficient, depending on the nature of the sequence). However, it's still a less than ideal solution for large sequences. I suggest writing your own MaxObject extension manually if you have a large set of items to be able to do it in one pass without sorting and other stuff whatsoever (O(n)):

static class EnumerableExtensions {     public static T MaxObject<T,U>(this IEnumerable<T> source, Func<T,U> selector)       where U : IComparable<U> {        if (source == null) throw new ArgumentNullException("source");        bool first = true;        T maxObj = default(T);        U maxKey = default(U);        foreach (var item in source) {            if (first) {                 maxObj = item;                 maxKey = selector(maxObj);                 first = false;            } else {                 U currentKey = selector(item);                 if (currentKey.CompareTo(maxKey) > 0) {                     maxKey = currentKey;                     maxObj = item;                 }            }        }        if (first) throw new InvalidOperationException("Sequence is empty.");        return maxObj;     } } 

and use it with:

var maxObject = list.MaxObject(item => item.Height); 
like image 40
mmx Avatar answered Oct 16 '22 21:10

mmx