结合两个LINQ查询的优雅方式

本文关键字:查询 方式 LINQ 两个 结合 | 更新日期: 2023-09-27 18:06:41

如何将这两个LINQ查询合并为一个?

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

结合两个LINQ查询的优雅方式

MaxBy是你正在寻找的:http://code.google.com/p/morelinq/source/browse/trunk/MoreLinq/MaxBy.cs像这样使用它:

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

EDIT 1:正如Jason指出的那样,这个方法只在使用LINQ to Objects时使用。如果您正在对数据库进行查询(因此您正在使用LINQ to SQL或其他),则应该考虑使用不同的方法。

你的看起来很好读,但是,如果它不满足你,你总是可以在IQueryable对象上调用AsEnumerable,然后使用MaxBy方法。

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

EDIT 2:您可以在查询中更改的一件事是第二个语句。尽量缩短它如下(为了避免使用Where):

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

注意,实际上最好使用而不使用 LINQ。只需循环遍历列表,跟踪最大日期和第一次发现该日期的项:

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

现在你只迭代一次,而不必承受排序的打击。

这确实假设您正在使用LINQ-to-Objects。如果不是,那么这将从数据库(或其他地方)检索整个集合,这是不希望的。在这种情况下,我会使用你已经有的方法。

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

对于Link-to-Objects(在Linq-to-Sql中不支持聚合)。执行N(N)(好的,实际上是O(N +1))

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

对于那些阅读有困难的人来说,第一个参数是累加器的初始值,它将正常聚合列表中的值,但这里只是保存当前最高的记录。然后,对于列表中的每条记录,调用lambda函数,给出当前最高的项和下一个项。

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