/// <summary> /// Returns the maximal element of a sequence based on a specified projection and comparer for projected /// values. /// </summary> /// <remarks> /// If more than one element has the maximal projected value, the first one encountered will be returned. This /// overload uses the default comparer for the projected type. This operator uses immediate execution, but only /// buffers a single result (the current maximal element). /// </remarks> /// <typeparam name="TSource">The type of source sequence.</typeparam> /// <typeparam name="TKey">The type of projected element.</typeparam> /// <param name="source">The source sequence.</param> /// <param name="selector">A transform function to apply to each element.</param> /// <param name="comparer">A comparer used to compare projected values.</param> /// <returns>The maximal element, according to the projection.</returns> /// <exception cref="ArgumentNullException"><paramref name="source"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentNullException"><paramref name="selector"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentNullException"><paramref name="comparer"/> is <see langword="null"/>.</exception> /// <exception cref="InvalidOperationException"><paramref name="source"/> is empty.</exception> public static TSource MaxBy <TSource, TKey>( this IEnumerable <TSource> source, Func <TSource, TKey> selector, IComparer <TKey> comparer) { source.AssertNotNull("source"); selector.AssertNotNull("selector"); comparer.AssertNotNull("comparer"); using (IEnumerator <TSource> sourceIterator = source.GetEnumerator()) { if (!sourceIterator.MoveNext()) { throw new InvalidOperationException("The sequence is empty."); } var max = sourceIterator.Current; var maxKey = selector(max); while (sourceIterator.MoveNext()) { var candidate = sourceIterator.Current; var candidateProjected = selector(candidate); if (comparer.Compare(candidateProjected, maxKey) > 0) { max = candidate; maxKey = candidateProjected; } } return(max); } }