2009-11-08 13 views
5

Diciamo che ho un oggetto:Rimuovere 3 elementi più vecchi da un elenco <> in C#

public class CustomObj 
{ 
    DateTime Date { get; set; } 
    String Name { get; set; } 
} 

Allora diciamo che ho una lista con 20 diversi elementi.

var stuff = new List<CustomObj> 
{ 
    { Date = DateTime.Now, Name = "Joe" }, 
    { Date = DateTime.Now.AddDays(1), Name = "Joe2" }, 
    { Date = DateTime.Now.AddDays(2), Name = "Joe3" }, 
    { Date = DateTime.Now.AddDays(3), Name = "Joe4" }, 
    { Date = DateTime.Now.AddDays(4), Name = "Joe5" }, 
    { Date = DateTime.Now.AddDays(5), Name = "Joe6" }, 
    { Date = DateTime.Now.AddDays(6), Name = "Joe7" }, 
    { Date = DateTime.Now.AddDays(7), Name = "Joe8" }, 
    { Date = DateTime.Now.AddDays(8), Name = "Joe9" }, 
    { Date = DateTime.Now.AddDays(9), Name = "Joe10" }, 
    { Date = DateTime.Now.AddDays(10), Name = "Joe11" } 
} 

Come rimuovere i 3 elementi più vecchi?

stuff.RemoveAll(item => ???) 
+0

se si scorre l'elenco per rimuovere gli elementi, assicurarsi di utilizzare un non un precursore. – jim

+0

Se "più vecchio" è per "first in", la soluzione più semplice dovrebbe essere un approccio "first-in, first-out": utilizzare un 'Queue'. –

+0

Ottima domanda, facile da capire il caso d'uso, e ha reso davvero facile per me come lettore trovare la risposta giusta. Grazie per avermi chiesto come hai fatto. – joelc

risposta

8

Se avete solo bisogno di enumerare gli elementi, questo funzionerà:

stuff.OrderBy(item => item.Date).Skip(3); 

Se effettivamente vuoi in lista devi chiamare .ToList() successivamente:

stuff = stuff.OrderBy(item => item.Date).Skip(3).ToList(); 
+1

non rimuove gli elementi, li salta semplicemente e fa cosa con il valore restituito? –

+0

Probabilmente vuole fare una .ToList() dopo di essa. – Dykam

+1

Non rimuove gli elementi dall'elenco sorgente, ma l'OP potrebbe assegnare il valore restituito a qualcos'altro, ad es. chiama ToList e quindi riassegna alla variabile 'stuff'. –

3

Se l'elenco è ordinato si può semplicemente utilizzare il metodo RemoveRange:

int n = 3; 
stuff.RemoveRange(stuff.Count - n, n); 
+3

dovrebbe essere ordinato prima, quindi rimuoviamo gli ultimi 3 –

1
const int cToRemove = 3; 

var top3 = (from c in stuff 
     orderby c.Date ascending 
     select c).Take(cToRemove); 
4

Se siete disposti a sostituire l'elenco con uno nuovo, si potrebbe provare questo:

stuff = stuff.OrderBy(c => c.Date).Skip(3).ToList(); 

D'altra parte, se avete bisogno di stuff rimanere la stessa istanza esatto List<T>, si poteva ordinare e poi rimuovere un intervallo in base all'indice:

stuff.Sort(...); 
stuff.RemoveRange(0, 3); 
1

Tutte le altre risposte finora hanno fatto affidamento su di ordinamento della lista, che è un O (n log n), se non lo avete già smistato.

Ecco una soluzione che è O (n) anche se con un fattore orribile costante. Utilizza MinBy da MoreLINQ - è possibile riscriverlo facilmente nel proprio codice, se necessario, e persino restituire l'indice direttamente anziché il valore (e utilizzare RemoveAt anziché Remove).

// The list.Count part is in case the list starts off with 
// fewer than 3 elements 
for (int i = 0; i < 3 && list.Count > 0; i++) 
{ 
    var oldest = list.MinBy(x => x.Date); 
    list.Remove(oldest); 
} 

si potrebbe certamente scrivere questo in modo più efficiente per trovare i più antichi tre elementi in un unico passaggio della lista - ma il codice sarebbe stato notevolmente più complessa, portando a più possibilità di errori. Quanto sopra dovrebbe funzionare bene in O (n), anche se manca di eleganza quando si pensa di passare attraverso la lista 6 volte :)

Problemi correlati