Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement MaxOrDefault(x => x.SomeInt) LINQ extension?

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?

like image 643
Brendan Hill Avatar asked Dec 31 '14 00:12

Brendan Hill


2 Answers

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.

like image 139
Lukazoid Avatar answered Nov 15 '22 03:11

Lukazoid


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 => ...);
like image 24
myermian Avatar answered Nov 15 '22 02:11

myermian