using System.Collections.Generic;
namespace System.Linq
{
public static class LINQ_SingleMinMax
{
/// <summary>
/// Wählt ein einzelnes Element aus, dessen bestimmter Wert das Minimum aller bestimmter Werte ist.
/// </summary>
/// <typeparam name="TResult">Der Typ der Elemente in der Quellauflistung.</typeparam>
/// <typeparam name="TComparable">Der Typ der zum Größenvergleich der Werte dient.</typeparam>
/// <param name="source">Die Quellliste mit den Elementen.</param>
/// <param name="predicate">Eine Funktion zum auswählen des bestimmten Wertes eines Elements.</param>
/// <returns>Das Element aus <paramref name="source"/> dessen mit <paramref name="predicate"/> bestimmter Wert Minimal ist.</returns>
/// <exception cref="System.ArgumentNullException">Wird ausgelöst, wenn einer der Parameter <c>null</c> ist.</exception>
/// <exception cref="System.InvalidOperationException">Wird ausgelöst, wenn <paramref name="source"/>
/// kein Element enthält oder aber mehr als eines, dessen Wert minimal ist.</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>
/// Wählt ein einzelnes Element aus, dessen bestimmter Wert das Maximum aller bestimmter Werte ist.
/// </summary>
/// <typeparam name="TResult">Der Typ der Elemente in der Quellauflistung.</typeparam>
/// <typeparam name="TComparable">Der Typ der zum Größenvergleich der Werte dient.</typeparam>
/// <param name="source">Die Quellliste mit den Elementen.</param>
/// <param name="predicate">Eine Funktion zum auswählen des bestimmten Wertes eines Elements.</param>
/// <returns>Das Element aus <paramref name="source"/> dessen mit <paramref name="predicate"/> bestimmter Wert Maximal ist.</returns>
/// <exception cref="System.ArgumentNullException">Wird ausgelöst, wenn einer der Parameter <c>null</c> ist.</exception>
/// <exception cref="System.InvalidOperationException">Wird ausgelöst, wenn <paramref name="source"/>
/// kein Element enthält oder aber mehr als eines, dessen Wert maximal ist.</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;
}
}
}