Come posso ottenere LINQ per restituire l’object che ha il valore massimo per una determinata proprietà?

Se ho una class che assomiglia a:

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

E una collezione di quegli oggetti …

 List items = getItems(); 

Come posso usare LINQ per restituire il singolo object “Item” che ha l’ID più alto?

Se faccio qualcosa come:

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

Riceverò solo l’ID più alto, quando ciò che voglio effettivamente restituito è l’object Item stesso che ha l’ID più alto? Voglio che restituisca un singolo object “Item”, non un int.

Questo passerà in loop solo una volta.

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

Grazie Nick – Ecco la prova

 class Program { static void Main(string[] args) { IEnumerable items1 = new List() { 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; } } 

Riorganizza la lista e ottieni lo stesso risultato

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

Per quanto riguarda le prestazioni, è molto probabile che questo metodo sia teoricamente più lento di un approccio lineare. Tuttavia, in realtà, il più delle volte non ci occupiamo del set di dati che è abbastanza grande da fare alcuna differenza.

Se la prestazione è una preoccupazione principale, la risposta di Seattle Leonard dovrebbe darti una complessità temporale lineare. In alternativa, puoi anche considerare di iniziare con una diversa struttura dati che restituisce la voce di valore massimo a tempo costante.

Usa MaxBy dal progetto morelinq :

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

Questo presuppone che ci siano elementi nella collezione di articoli, ovviamente.

Nel caso in cui non si desideri utilizzare MoreLINQ e si desideri ottenere il tempo lineare, è ansible utilizzare anche 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; 

Questo memorizza l’elemento massimo corrente ( Item ) e il valore massimo corrente ( Item ) in un tipo anonimo. Quindi scegli la proprietà Item . Questo è davvero un po ‘brutto e si potrebbe avvolgere nel metodo di estensione MaxBy per ottenere la stessa cosa con MoreLINQ:

 public static T MaxBy(this IEnumerable items, Func 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; } 

Oppure puoi scrivere il tuo metodo di estensione:

 static partial class Extensions { public static T WhereMax(this IEnumerable items, Func selector) { if (!items.Any()) { throw new InvalidOperationException("Empty input sequence"); } var comparer = Comparer.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; } } 

prova questo:

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

Potresti usare una variabile catturata.

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

In LINQ puoi risolverlo nel seguente modo:

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

Questo è un metodo di estensione derivato dalla risposta di @Seattle Leonard:

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