tags:

views:

211

answers:

2

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();

What's the neatest way to set the result to 0 if the list is empty?

+6  A: 
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 >.

Marc Gravell
interesting. I can't work out how this would avoid an empty list but I'll give it a try
Chris Simpson
Try it: `decimal? result = (new decimal?[0]).Min();` gives `null`
Marc Gravell
and perhaps then use ?? 0 to get the desired result?
Lette
It definitely works. I've just built a unit test to try it out, but I'm going to have to take 5 minutes working out why the result of the select is a single null value rather than an empty list (it's possible my sql background confusing me). Thanks for this.
Chris Simpson
@Lette, if I change it to: decimal result1 = .....Min() ?? 0; this works too, so thanks for your input.
Chris Simpson
+10  A: 

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!

Lette
damn, that's so obvious now you say it, thank you. I may actually go with: ...DefaultIfEmpty(decimal.MaxValue).Min()
Chris Simpson
I like your answer best. I think the other solution might be much slower because of boxing/unboxing.
Christo