开发者

Remove 3 oldest elements from a List<> in C#

Let's say I have an object:

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

Then let's say I have a List with 20 various elements.

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

How can I remove the 3 old开发者_如何学编程est elements?

stuff.RemoveAll(item => ???)


If you only need to enumerate the items, this will work:

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

If you actually want it in list form you will have to call .ToList() afterwards:

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


If you're willing to replace the list with a new one, you could try this:

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

On the other hand, if you need stuff to remain the same exact List<T> instance, you could sort it and then remove a range by index:

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


If your list is ordered you could simply use the RemoveRange method:

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


const int cToRemove = 3;

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


All the other answers so far have relied on sorting the list, which is an O(n log n) operation if you don't already have it sorted.

Here's a solution which is O(n) albeit it with a horrible constant factor. It uses MinBy from MoreLINQ - you could easily rewrite that in your own code if you need to, and even make it return the index directly instead of the value (and useRemoveAt instead of 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);
}

You could certainly write this more efficiently to find the oldest three elements in a single pass of the list - but the code would be significantly more complicated, leading to more chances for errors. The above should work fine in O(n), even if it's lacking in elegance when you think of it going through the list 6 times :)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜