2009-11-08 14 views
5

Powiedzmy mam obiektu:Usuń 3 najstarsze elementy z listy <> w C#

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

Wtedy powiedzmy mam listę z 20 różnych elementów.

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" } 
} 

Jak mogę usunąć 3 najstarsze elementy?

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

jeśli przeglądasz listę, aby usunąć elementy, upewnij się, że używasz nie foreeach. – jim

+0

Jeśli "najstarszy" jest dla "pierwszego w", najprostszym rozwiązaniem powinno być podejście "pierwsze przyszło, pierwsze wyszło": użyj 'Kolejki'. –

+0

Doskonałe pytanie, łatwy do zrozumienia przypadek użycia i bardzo ułatwiłem mi jako czytelnikowi znalezienie właściwej odpowiedzi. Dziękuję za pytanie, jak to zrobiłeś. – joelc

Odpowiedz

8

Jeśli tylko trzeba wymienić elementy, to będzie działać:

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

jeśli rzeczywiście chcesz go w formie listy musisz zadzwonić .ToList() następnie:

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

nie usuwa przedmiotów, po prostu je pomija i robi to, co z wartością zwracaną? –

+0

Prawdopodobnie chce zrobić .ToList() po tym. – Dykam

+1

Nie usuwa elementów z listy źródłowej, ale OP może przypisać wartość zwracaną do czegoś innego, np. wywołaj ToList, a następnie ponownie przypisz do zmiennej 'stuff'. –

3

Jeśli lista jest sortowana można po prostu użyć metody RemoveRange:

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

należy najpierw zamówić, a następnie usunąć ostatnie 3 –

1
const int cToRemove = 3; 

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

Jeśli jesteś gotów zastąpić listę z nowym, można spróbować to:

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

Z drugiej strony, jeśli trzeba stuff pozostaje dokładnie taki sam List<T> instancja, można je posortować, a następnie usunąć szereg przez index:

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

Wszystkie inne odpowiedzi do tej pory opierały się na sortowanie listy, która jest o (n log n) operacji, jeśli nie ma go już posortowane.

Oto rozwiązanie, które jest O (n), ale z okropnym stałym czynnikiem. Używa ona MinBy z MoreLINQ - możesz z łatwością przepisać to w swoim własnym kodzie, jeśli zajdzie taka potrzeba, a nawet sprawić, by zwrócił on bezpośrednio indeks zamiast wartości (i używał RemoveAt zamiast 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); 
} 

Można oczywiście napisać to bardziej efektywnie znaleźć najstarsze trzy elementy w jednym przejściu listy - ale kod byłby znacznie bardziej skomplikowana, co prowadzi do większej liczby szans na błędy. Powyższe powinno działać poprawnie w O (n), nawet jeśli brakuje mu elegancji, gdy myślisz o przechodzeniu przez listę 6 razy :)

Powiązane problemy