Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is faster in finding element with property of maximum value

Commonly, to find element with property of max value I do like this

var itemWithMaxPropValue = collection.OrderByDescending(x => x.Property).First();

But is it good way from performance point of view? Maybe I should do something like this?

var maxValOfProperty = collection.Max(x => x.Property);
var itemWithMaxPropValue = collection
                                 .Where(x => x.Property == maxValueOfProperty).First();
like image 417
Konstantin Zadiran Avatar asked Feb 17 '16 15:02

Konstantin Zadiran


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 to find the max/min value of an element?

There's no way to find the maximum / minimum in the general case without looping through all the n elements (if you go from, 1 to n-1, how do you know whether the element n isn't larger (or smaller) than the current max/min)? You mentioned that the values change every couple of seconds.

How to find the maximum value in a map in C++?

This post will discuss how to find an element with the maximum value in a map in C++. 1. Using std::max_element The recommended solution is to use the std::max_element to find an element having the maximum value in a map. It returns an iterator pointing to an element with the maximum value in the specified range.

How to select object with minimum or maximum property value?

IF you want to select object with minimum or maximum property value. another way is to use Implementing IComparable. Max Implementation will be. Min Implementation will be. In this way, you can compare any object and get the Max and Min while returning the object type. Hope This will help someone.

How to search the max value of an attribute in array?

How to search the max value of an attribute in an array object ? Maximum value of an attribute in an array of objects can be searched in two ways, one by traversing the array and the other method is by using the Math.max.apply () method.


5 Answers

Sorting is N * log (N) while Max has N only time complexity, so Max is faster. What you're looking for is ArgMax function which Linq doesn't provide, so I suggest implementing it, e.g:

  public static class EnumerableExtensions {
    public static T ArgMax<T, K>(this IEnumerable<T> source, 
                                 Func<T, K> map, 
                                 IComparer<K> comparer = null) {
      if (Object.ReferenceEquals(null, source))
        throw new ArgumentNullException("source");
      else if (Object.ReferenceEquals(null, map))
        throw new ArgumentNullException("map");

      T result = default(T);
      K maxKey = default(K);
      Boolean first = true;

      if (null == comparer)
        comparer = Comparer<K>.Default;

      foreach (var item in source) {
        K key = map(item);

        if (first || comparer.Compare(key, maxKey) > 0) {
          first = false;
          maxKey = key;
          result = item;
        }
      }

      if (!first)
        return result;
      else
        throw new ArgumentException("Can't compute ArgMax on empty sequence.", "source");
    }
  }

So you can put it simply

  var itemWithMaxPropValue = collection
    .ArgMax(x => x.Property);
like image 166
Dmitry Bychenko Avatar answered Oct 16 '22 10:10

Dmitry Bychenko


Both solutions are not very efficient. First solution involves sorting whole collection. Second solution requires traversing collection two times. But you can find item with max property value in one go without sorting collection. There is MaxBy extension in MoreLINQ library. Or you can implement same functionality:

public static TSource MaxBy<TSource, TProperty>(this IEnumerable<TSource> source,
    Func<TSource, TProperty> selector)
{
    // check args        

    using (var iterator = source.GetEnumerator())
    {
        if (!iterator.MoveNext())            
            throw new InvalidOperationException();

        var max = iterator.Current; 
        var maxValue = selector(max);
        var comparer = Comparer<TProperty>.Default;

        while (iterator.MoveNext())
        {
            var current = iterator.Current;
            var currentValue = selector(current);

            if (comparer.Compare(currentValue, maxValue) > 0)
            {
                max = current;
                maxValue = currentValue;
            }
        }

        return max;
    }
}

Usage is simple:

var itemWithMaxPropValue = collection.MaxBy(x => x.Property); 
like image 20
Sergey Berezovskiy Avatar answered Oct 16 '22 09:10

Sergey Berezovskiy


I will go with Max since it is specifically designed for that purpose. Sorting to find Max value seems to be too much.

Also, I wouldn't use Where for finding the max, but Single - since what we need here is but a Single value.

var maxValOfProperty = collection.Max(x => x.Property);
var itemWithMaxPropValue = collection
                            .Single(x => x.Property == maxValueOfProperty);

Or alternatively using First (if the collection contains duplicates of max value)

var maxValOfProperty = collection.Max(x => x.Property);
var itemWithMaxPropValue = collection
                            .First(x => x.Property == maxValueOfProperty);

Or, using MoreLINQ (as suggested by Kathi), you could do it with MaxBy:

var itemWithMaxPropValue = collection.MaxBy(x => x.Property);

Check this post, on answer by Jon Skeet.

like image 26
Ian Avatar answered Oct 16 '22 10:10

Ian


The maximum element under some specified function can also be found by means of the following two functions.

static class Tools
{
    public static T ArgMax<T, R>(T t1, T t2, Func<T, R> f)
    where R : IComparable<R>
    {
        return f(t1).CompareTo(f(t2)) > 0 ? t1 : t2;
    }

    public static T ArgMax<T, R>(this IEnumerable<T> Seq, Func<T, R> f)
    where R : IComparable<R>
    {
        return Seq.Aggregate((t1, t2) => ArgMax<T, R>(t1, t2, f));
    }
}

The solution above works as follows; the first overload of ArgMax takes a comparator as an argument which maps both instances of T to a type which implements comparability; a maximum of these is returned. The second overload takes a sequence as an argument and simply aggregates the first function. This is the most generic, framework-reusing and structurally sound formulation for maximum search I am aware of; searching the minimum can be implemented in the same way by changing the comparison in the first function.

like image 39
Codor Avatar answered Oct 16 '22 10:10

Codor


I'm a little bit surprised that no one mentioned the Aggregate method. Aggregate lets you iterate a collection and return an aggregate value.

An ArgMax function can be implemented in this way:

var maxItem = collection.Aggregate((max, next) => next.Property.CompareTo(max.Property) > 0 ? next : max);

This function will iterate all over the collection and aggregate the item that has the largest Property. This implementation is O(N) which is good.

Please note that the Property getter (or the compared value in general) is called 2N times so don't do this when the value computation is heavy. You can avoid this with another iteration over the array or use the @Sergey Berezovskiy answer which suits all the cases.

But if you need it for simple values, this is a one-line efficient solution

like image 28
nrofis Avatar answered Oct 16 '22 09:10

nrofis