user424134
user424134

Reputation: 532

Elegant way of combining two LINQ queries

How can I combine these two LINQ queries in one?

var maxEndDate = lstDates.Select(s => s.EndDate).Max();    
var record = lstDates.Where(s => s.EndDate == maxEndDate).First();

Upvotes: 8

Views: 186

Answers (6)

James Curran
James Curran

Reputation: 103575

For Link-to-Objects (Aggregate not supported in Linq-to-Sql). Performs in N(n) (ok, actually O(n+1))

var record = lstDates.Aggregate(lstDates.First(), 
                                (mx, i) => i.EndDate > mx.EndDate ? i : mx));

For those having trouble reading that, the first parameter is the initial value for the accumulator, which would normal aggregate values in the list, but here is just holding the current highest record. Then for each record in the list, the lambda function is called, given the current highest and the next item. It returns the new current highest.

Upvotes: 1

as-cii
as-cii

Reputation: 13039

MaxBy is what you are looking for: http://code.google.com/p/morelinq/source/browse/trunk/MoreLinq/MaxBy.cs using it like this:

var record = lstDates.MaxBy(a => a.EndDate);

EDIT 1: As Jason pointed out this method is intended to be used only when you are working with LINQ to Objects. If you are querying against a database (and so you are using LINQ to SQL, or whatever) you should consider using a different approach.

Yours seems quite readable but, if it doesn't satisfy you, you could always call AsEnumerable on the IQueryable object and then use MaxBy method.

var record = lstDates.AsEnumerable().MaxBy(a => a.EndDate);

EDIT 2: One thing you could change in your query is the second statement. Try to shorten it as follows (in order to avoid using Where):

var record = lstDates.First(s => s.EndDate == maxEndDate);

Upvotes: 8

doowb
doowb

Reputation: 3372

var record = (from r in lstDates
              orderby r.EndDate descending
              select r).First();

Upvotes: 1

dlev
dlev

Reputation: 48596

Note that is actually best done without LINQ. Just loop through the list, keeping track of the maximum date, and the item at which that was first found:

DateTime maxDate = default(DateTime);
YourClass maxItem = null;

foreach (var item in lstDates)
{
    if (item.EndDate > maxDate)
    {
        maxDate = item.EndDate;
        maxItem = item;
    }
}

Now you only iterate once, and don't have to take the hit of sorting.

This does assume that you're using LINQ-to-Objects. If you're not, then this will retrieve the entire collection from the database (or wherever) which is undesirable. In that case, I would just use the method you already have.

Upvotes: 1

Kevin Kalitowski
Kevin Kalitowski

Reputation: 6989

var record = lstDates.OrderByDescending(d => d.EndDate).First();

Upvotes: 2

Matt McHugh
Matt McHugh

Reputation: 4095

var record = lstDates.Where(s => s.EndDate == lstDates.Max(v => v.EndDate)).First();

Upvotes: -1

Related Questions