C# - LINQ Extension: SingleMin/SingleMax

By , 8/29/2015
(1 ratings)
This extension methods select single elements from a sequence. These elements has a defined value which is minimal respective maximal.
These defined values can be seected for each item with a provided function.

Hint: This methods works roughly like the Min/Max methods. But my Versions select the item, not the max/min value.
Translate to VB
using System.Collections.Generic;

namespace System.Linq
{
    public static class LINQ_SingleMinMax
    {
        /// <summary>
        /// Returns the only element of a sequence that satisfies the condition that a defined value is the minimum of all.
        /// </summary>
        /// <typeparam name="TResult">The typ of the items in the source list.</typeparam>
        /// <typeparam name="TComparable">The typ that is used for comparison of the values. It must implement <see cref="System.IComparable{T}"/>.</typeparam>
        /// <param name="source">The source list.</param>
        /// <param name="predicate">A function that extracts a key for value comparison.</param>
        /// <returns>The only element from <paramref name="source"/> which with <paramref name="predicate"/> defined value minimal is.</returns>
        /// <exception cref="System.ArgumentNullException">Is thrown if one parameter is <c>null</c>.</exception>
        /// <exception cref="System.InvalidOperationException">Is thrown if the sequence is empty or contains more than one possible result.</exception>
        public static TResult SingleMin<TResult, TComparable>(this IEnumerable<TResult> source, Func<TResult, TComparable> predicate)
            where TComparable : IComparable<TComparable>
        {
            return SelectMinMax(source, predicate, 1);
        }

        /// <summary>
        /// Returns the only element of a sequence that satisfies the condition that a defined value is the maximum of all.
        /// </summary>
        /// <typeparam name="TResult">The typ of the items in the source list.</typeparam>
        /// <typeparam name="TComparable">The typ that is used for comparison of the values. It must implement <see cref="System.IComparable{T}"/>.</typeparam>
        /// <param name="source">The source list.</param>
        /// <param name="predicate">A function that extracts a key for value comparison.</param>
        /// <returns>The only element from <paramref name="source"/> which with <paramref name="predicate"/> defined value maximal is.</returns>
        /// <exception cref="System.ArgumentNullException">Is thrown if one parameter is <c>null</c>.</exception>
        /// <exception cref="System.InvalidOperationException">Is thrown if the sequence is empty or contains more than one possible result.</exception>
        public static TResult SingleMax<TResult, TComparable>(this IEnumerable<TResult> source, Func<TResult, TComparable> predicate)
            where TComparable : IComparable<TComparable>
        {
            return SelectMinMax(source, predicate, -1);
        }

        private static TResult SelectMinMax<TResult, TComparable>(IEnumerable<TResult> source, Func<TResult, TComparable> predicate, int compareToResult)
            where TComparable : IComparable<TComparable>
        {
            if (source == null)
            {
                throw new ArgumentNullException("source", "Source connot be null.");
            }
            if (predicate == null)
            {
                throw new ArgumentNullException("predicate", "predicate connot be null.");
            }
            var item = source.FirstOrDefault();
            if (item == null)
            {
                throw new InvalidOperationException("The Sequence is empty");
            }
            var key = predicate(item);
            bool foundMultipleOccurences = false;
            foreach (var inner in source.Skip(1))
            {
                var innerKey = predicate(inner);
                var compareResult = key.CompareTo(innerKey);
                if (compareResult == compareToResult)
                {
                    item = inner;
                    key = innerKey;
                    foundMultipleOccurences = false;
                }
                else if (compareResult == 0)
                {
                    foundMultipleOccurences = true;
                }
            }
            if (foundMultipleOccurences)
            {
                throw new InvalidOperationException("The Sequence contain more than one matching elements.");
            }
            return item;
        }
    }
}
Tagged with LINQ, Extension, Single, Min, Max.

Comments

 

Log in, to comment!