How to achieve "MinOrDefault" in LINQ?

Viewed 29911

I'm producing a list of decimal values from a LINQ expression and I want the minimum non zero value. However it's entirely possible that the LINQ expression will result in an empty list.

This will raise an exception and there is no MinOrDefault to cope with this situation.

decimal result = (from Item itm in itemList
                  where itm.Amount > 0
                  select itm.Amount).Min();

How can I set the result to 0 if the list is empty?

6 Answers

What you want is this:

IEnumerable<double> results = ... your query ...

double result = results.MinOrDefault();

Well, MinOrDefault() does not exist. But if we were to implement it ourselves it would look something like this:

public static class EnumerableExtensions
{
    public static T MinOrDefault<T>(this IEnumerable<T> sequence)
    {
        if (sequence.Any())
        {
            return sequence.Min();
        }
        else
        {
            return default(T);
        }
    }
}

However, there is functionality in System.Linq that will produce the same result (in a slightly different way):

double result = results.DefaultIfEmpty().Min();

If the results sequence contains no elements, DefaultIfEmpty() will produce a sequence containing one element - the default(T) - which you subsequently can call Min() on.

If the default(T) is not what you want, then you could specify your own default with:

double myDefault = ...
double result = results.DefaultIfEmpty(myDefault).Min();

Now, that's neat!

decimal? result = (from Item itm in itemList
                  where itm.Amount != 0
                  select (decimal?)itm.Amount).Min();

Note the conversion to decimal?. You'll get an empty result if there are none (just handle that after the fact - I'm mainly illustrating how to stop the exception). I also made "non-zero" use != rather than >.

If itemList is non-nullable (where DefaultIfEmpty gives 0) and you want null as a potential output value, you can use the lambda syntax as well:

decimal? result = itemList.Where(x => x.Amount != 0).Min(x => (decimal?)x);
decimal result;
try{
  result = (from Item itm in itemList
                  where itm.Amount != 0
                  select (decimal?)itm.Amount).Min();
}catch(Exception e){
  result = 0;
}
Related