我怎样才能让LINQ返回给定属性的最大值的对象?

如果我有一个类似于以下的类:

public class Item { public int ClientID { get; set; } public int ID { get; set; } } 

和这些项目的集合…

 List<Item> items = getItems(); 

我如何使用LINQ返回具有最高ID的单个“Item”对象?

如果我做这样的事情:

 items.Select(i => i.ID).Max(); 

我只会得到最高的ID,当我真正想要返回的是ID对象本身具有最高的ID? 我希望它返回一个“Item”对象,而不是一个int。

这将只循环一次。

 Item biggest = items.Aggregate((i1,i2) => i1.ID > i2.ID ? i1 : i2); 

谢谢尼克 – 这是certificate

 class Program { static void Main(string[] args) { IEnumerable<Item> items1 = new List<Item>() { new Item(){ ClientID = 1, ID = 1}, new Item(){ ClientID = 2, ID = 2}, new Item(){ ClientID = 3, ID = 3}, new Item(){ ClientID = 4, ID = 4}, }; Item biggest1 = items1.Aggregate((i1, i2) => i1.ID > i2.ID ? i1 : i2); Console.WriteLine(biggest1.ID); Console.ReadKey(); } } public class Item { public int ClientID { get; set; } public int ID { get; set; } } 

重新排列列表并获得相同的结果

使用morelinq项目中的MaxBy :

 items.MaxBy(i => i.ID); 
 int max = items.Max(i => i.ID); var item = items.First(x => x.ID == max); 

这假定当然在项目集合中有元素。

 .OrderByDescending(i=>i.id).Take(1) 

关于性能问题,这种方法很可能在理论上比线性方法慢。 但实际上,大多数情况下,我们并没有处理足够大的数据集来产生任何影响。

如果performance是一个主要问题,西雅图伦纳德的答案应该给你线性时间复杂性。 或者,您也可以考虑从不同的数据结构开始,在不同的时间返回最大值。

如果您不想使用MoreLINQ并想要获得线性时间,也可以使用Aggregate

 var maxItem = items.Aggregate( new { Max = Int32.MinValue, Item = (Item)null }, (state, el) => (el.ID > state.Max) ? new { Max = el.ID, Item = el } : state).Item; 

这会记住匿名types中的当前最大元素( Item )和当前最大值( Item )。 然后你只需selectItem属性。 这确实有点难看,你可以把它换成MaxBy扩展方法来获得和MoreLINQ一样的function:

 public static T MaxBy(this IEnumerable<T> items, Func<T, int> f) { return items.Aggregate( new { Max = Int32.MinValue, Item = default(T) }, (state, el) => { var current = f(el.ID); if (current > state.Max) return new { Max = current, Item = el }; else return state; }).Item; } 

或者你可以写你自己的扩展方法:

 static partial class Extensions { public static T WhereMax<T, U>(this IEnumerable<T> items, Func<T, U> selector) { if (!items.Any()) { throw new InvalidOperationException("Empty input sequence"); } var comparer = Comparer<U>.Default; T maxItem = items.First(); U maxValue = selector(maxItem); foreach (T item in items.Skip(1)) { // Get the value of the item and compare it to the current max. U value = selector(item); if (comparer.Compare(value, maxValue) > 0) { maxValue = value; maxItem = item; } } return maxItem; } } 

尝试这个:

 var maxid = from i in items group i by i.clientid int g select new { id = g.Max(i=>i.ID } 

你可以使用捕获的variables。

 Item result = items.FirstOrDefault(); items.ForEach(x => { if(result.ID < x.ID) result = x; }); 

在LINQ中,你可以用下面的方法解决它:

 Item itemMax = (from i in items let maxId = items.Max(m => m.ID) where i.ID == maxId select i).FirstOrDefault(); 

这是一个来自@Seattle Leonard的答案的扩展方法:

  public static T GetMax<T,U>(this IEnumerable<T> data, Func<T,U> f) where U:IComparable { return data.Aggregate((i1, i2) => f(i1).CompareTo(f(i2))>0 ? i1 : i2); }