È possibile utilizzare GroupBy
, quindi ordinare questo V1-V2 da gruppo:
var highestItemByV1V2 = list.GroupBy(x => x.V1)
.OrderByDescending(g => g.Key)
.Select(g => g.OrderByDescending(x => x.V2).First())
.First();
Si dovrebbe anche memorizzare il valore massimo invece di usarlo come espressione nella query, altrimenti sarà evaulated sempre. Quindi questo è più efficiente:
var highestV1 = list.Max(x => x.V1);
var maxObj = list.Where(x => x.V1 == highestV1).OrderByDescending(x => x.V2).First();
Tuttavia, il vostro primo approccio dovrebbe funzionare bene, è semplice ed efficace:
list.OrderByDescending(e => e.V1).ThenByDescending(e => e.V2).First();
Quindi, che tipo di problema di prestazioni avete? Forse stai sbagliando nel posto sbagliato o chiami questo codice troppo spesso. Considera di memorizzarli già ordinati, per esempio in un SortedList
. Penso che uno SortedDictionary
sia anche more efficient in questo caso.
La classe generica SortedDictionary<TKey, TValue>
è un binario di ricerca albero con O (log n) di recupero, dove n è il numero di elementi nel dizionario . A tale proposito, è simile alla classe generica SortedList<TKey, TValue>
. Le due classi hanno modelli di oggetti simili, ed entrambi hanno O (log n) recupero. Dove i due classi differiscono è in uso della memoria e la velocità di inserimento e rimozione:
SortedList<TKey, TValue>
utilizza meno memoria SortedDictionary<TKey, TValue>
.
SortedDictionary<TKey, TValue>
ha operazioni di inserimento e rimozione più veloci per dati non ordinati: O (log n) in contrapposizione a O (n) per SortedList<TKey, TValue>
.
- Se l'elenco viene popolato tutti insieme da dati ordinati,
SortedList<TKey, TValue>
è più veloce di SortedDictionary<TKey, TValue>
.
Ecco una possibile implementazione utilizzando un SortedDictionary<double, SortedSet<Obj>>
:
SortedDictionary<double, SortedSet<Obj>> sortedLookup =
new SortedDictionary<double, SortedSet<Obj>>(); // key is V1 and value all items with that value
internal class ObjV2Comparer : IComparer<Obj>
{
public int Compare(Obj x, Obj y)
{
return x.V2.CompareTo(y.V2);
}
}
private static readonly ObjV2Comparer V2Comparer = new ObjV2Comparer();
public void Add(Obj obj)
{
SortedSet<Obj> set;
bool exists = sortedLookup.TryGetValue(obj.V1, out set);
if(!exists)
set = new SortedSet<Obj>(V2Comparer);
set.Add(obj);
sortedLookup[obj.V1] = set;
}
public Obj GetMaxItem()
{
if (sortedLookup.Count == 0) return null;
Obj maxV1Item = sortedLookup.Last().Value.Last();
return maxV1Item;
}
Obj
è la classe che contiene V1
e V2
, ho presunto che V1
è un tipo primitivo come double
. GetMaxItem
è il metodo che restituisce il max-item.
Se V1
eV2
può contenere duplicati si potrebbe provare questo approccio, in cui la chiave di ogni SortedDictionary
è il valore V1
e il valore è un altro SortedDictionary
con il tasto V2
e tutti gli oggetti correlati.
SortedDictionary<double, SortedDictionary<double, List<Obj>>> sortedLookup =
new SortedDictionary<double, SortedDictionary<double, List<Obj>>>();
public void Add(Obj obj)
{
SortedDictionary<double, List<Obj>> value;
bool exists = sortedLookup.TryGetValue(obj.V1, out value);
if(!exists)
{
value = new SortedDictionary<double, List<Obj>>(){{obj.V2, new List<Obj>{obj}}};
sortedLookup.Add(obj.V1, value);
}
else
{
List<Obj> list;
exists = value.TryGetValue(obj.V2, out list);
if (!exists)
list = new List<Obj>();
list.Add(obj);
value[obj.V2] = list;
sortedLookup[obj.V1] = value;
}
}
public Obj GetMaxItem()
{
if (sortedLookup.Count == 0) return null;
Obj maxV1Item = sortedLookup.Last().Value.Last().Value.Last();
return maxV1Item;
}
'myList.OrderByDescending (a => a.MyProperty) .OrderByDescending (b => b.MyProperty2) .Prima()' dovrebbe essere sublte. –
Un'altra possibilità sarebbe quella di implementare un proprio comparatore per il tuo oggetto che ordina gli oggetti per V1 prima e V2 per secondo e poi ordina la tua lista. – LInsoDeTeh
Come lavorare con un già [SortedList] (https://msdn.microsoft.com/library/ms132319.aspx), o ereditare da 'Elenco' e avere una proprietà 'Max' che viene aggiornata su ogni' Aggiungi' ? - aggiungerebbe penalità durante il riempimento, ma l'accesso sarebbe più veloce. –
Corak