2009-11-08 3 views
5

Допустим, у меня есть объект:Удалить 3 старые элементы из List <> в C#

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

Тогда давайте говорить, у меня есть список с 20 различных элементов.

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

Как удалить 3 самых старых элемента?

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

если вы перебираете список для удаления предметов, убедитесь, что вы используете для и а не предсказание. – jim

+0

Если «oldest» для «first in», самым простым решением должен быть подход «первый-в-первом»: используйте «Queue». –

+0

Отличный вопрос, простой для понимания вариант использования, и сделал это очень легко для меня, как читателя, чтобы найти правильный ответ. Спасибо, что спросили, как вы это делали. – joelc

ответ

8

Если вам нужно только перечислить пункты, это будет работать:

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

Если вы на самом деле хотите в форме списка, вам нужно будет позвонить по телефону .ToList() после этого:

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

, он не удаляет элементы, просто пропускает их и делает с возвращаемым значением? –

+0

Он, вероятно, захочет сделать .ToList() после него. – Dykam

+1

Он не удаляет элементы из исходного списка, но ОП может назначить возвращаемое значение чему-то еще, например. вызовите ToList, а затем переназначьте переменную 'stuff'. –

3

Если список упорядочен вы могли бы просто использовать RemoveRange метод:

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

его нужно заказывать первым, затем мы удаляем последние 3 –

1
const int cToRemove = 3; 

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

Если вы готовы заменить список с новым, вы можете попробовать это:

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

С другой стороны, если вам нужно stuff оставаться точно такой же List<T> экземпляр, вы можете отсортировать и удалить его диапазон по индексу:

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

Все остальные ответы до сих пор полагались на сортировку списка, который является O (п § п) операции, если вы уже не имеете его отсортирован.

Вот решение, которое является O (n), хотя и с ужасным постоянным коэффициентом. Он использует MinBy от MoreLINQ - вы можете легко переписать это в свой собственный код, если вам нужно, и даже заставить его возвращать индекс непосредственно вместо значения (и использовать RemoveAt вместо 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); 
} 

Вы могли бы, конечно, написать это более эффективно, чтобы найти самые старые три элемента в один проход списка - но код будет значительно более сложным, что приводит к больше шансов на наличие ошибок. Вышеприведенное должно отлично работать в O (n), даже если оно отсутствует в элегантности, когда вы думаете, что он проходит через список 6 раз :)