Chris
Chris

Reputation: 37

Subtracting properties in a list using LINQ

I have the following: (C# code, VS2013)

class DailyTemp
{
    public int Day;
    public int LowTemp;
    public int HighTemp;
}

List<DailyTemp> dailyTemps = new List<DailyTemp>();
//I fill this list with DailyTemp objects

My questions is, how do I write a lambda expression to go through my list and return the day that has the smallest difference between high and low temps? Thank you for your time.

Upvotes: 0

Views: 1860

Answers (3)

Ryan Nigro
Ryan Nigro

Reputation: 4619

Try:

return dailyTemps.OrderBy(dt => dt.HighTemp - dt.LowTemp).Select(dt => dt.Day).First();

As noted by @Colin DeClue, it's more efficient to call Select before First so that we're retrieving the minimum needed information from the data source (which can matter on larger data sets coming from a DB).

Upvotes: 9

Anthony Pegram
Anthony Pegram

Reputation: 126814

If you want to do an approach with a single pass over the sequence and using built-in methods, you can leverage Enumerable.Aggregate and keep the argument with the lowest temperature difference, discarding the other.

Func<DailyTemp, int> tempDiff = x => x.HighTemp - x.LowTemp;    
var day = dailyTemps.Aggregate((a, b) => tempDiff(a) < tempDiff(b) ? a : b);

Otherwise, MoreLinq's MinBy might read simpler (externally available API), as well as the OrderBy method available within the BCL (that requires sorting), each approach being highlighted in other visible answers.

Upvotes: 2

Servy
Servy

Reputation: 203823

We can use the MinBy method of MoreLINQ (argument validation removed below) to get the min value of a collection based on the value of a selector:

public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source,
    Func<TSource, TKey> selector)
{
    return source.MinBy(selector, Comparer<TKey>.Default);
}
public static TSource MinBy<TSource, TKey>(this IEnumerable<TSource> source,
    Func<TSource, TKey> selector, IComparer<TKey> comparer)
{
    using (IEnumerator<TSource> sourceIterator = source.GetEnumerator())
    {
        if (!sourceIterator.MoveNext())
        {
            throw new InvalidOperationException("Sequence was empty");
        }
        TSource min = sourceIterator.Current;
        TKey minKey = selector(min);
        while (sourceIterator.MoveNext())
        {
            TSource candidate = sourceIterator.Current;
            TKey candidateProjected = selector(candidate);
            if (comparer.Compare(candidateProjected, minKey) < 0)
            {
                min = candidate;
                minKey = candidateProjected;
            }
        }
        return min;
    }
}

This lets us write:

var day = dailyTemps.MinBy(dt => dt.HighTemp - dt.LowTemp);

Upvotes: 0

Related Questions