When calling .Max(x => x.SomeInt) on an IEnumerable, you commonly are happy to return "0" if the enumerable contains no elements. However LINQ's implementation of .Max(x => x.SomeInt) crashes as the sequence contains no elements.
Therefore a .MaxOrDefault(x => x.SomeInt) function would be useful.
We should not simply call .Any() then .Max(func) because this causes a legitimate "possible multiple enumeration" warning in Resharper.
I have implemented one as follows:
public static TResult MaxOrDefault<T, TResult>(this IEnumerable<T> enumerable, Func<T, TResult> func)
{
var list = enumerable.ToList();
if (!list.Any()) return default(TResult);
return list.Max(func);
}
However this has the downside of having to enumerate into a list first, which is suboptimal and should be unnecessary.
Is there a better way?
Here is what I consider a better/neater implementation:
public static TResult MaxOrDefault<T, TResult>(this IEnumerable<T> enumerable, Func<T, TResult> func)
{
return enumerable.Select(func).DefaultIfEmpty().Max();
}
DefaultIfEmpty
ensures if there are no elements, an IEnumerable
is returned containing a single default value, which will be of the value default(TResult)
, i.e. 0 for the numeric value types.
If you use the DefaultIfEmpty()
extension you will always be guaranteed to have a sequence of at least one item (the default item) if the sequence was empty.
var enumeration = ...;
var max = enumeration.DefaultIfEmpty().Max(x => ...);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With