在C#中从List<>中删除最旧的3个元素

5

假设我有一个对象:

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

如何删除最旧的三个元素?
stuff.RemoveAll(item => ???)

如果您要迭代列表以删除项目,请确保使用for而不是foreach。 - jim
如果“oldest”表示“最先进入”,最简单的解决方案应该是采用“先进先出”的方法:使用一个Queue - Mathieu Guindon
很棒的问题,使用案例易于理解,并且使我作为读者轻松找到了正确的答案。感谢您以这种方式提问。 - joelc
5个回答

8
如果你只需要列举项目,这个方法可以使用:
stuff.OrderBy(item => item.Date).Skip(3);

如果你实际上想要以列表形式呈现,则必须在之后调用.ToList()
stuff = stuff.OrderBy(item => item.Date).Skip(3).ToList();

1
它不会删除这些项目,只是跳过它们并返回什么值? - Johannes Rudolph
他可能想在此之后执行 .ToList()。 - Dykam
1
它不会从源列表中删除项目,但是OP可以将返回值分配给其他内容,例如调用ToList然后重新分配给“stuff”变量。 - Jon Skeet
没错。这不是最高效的方法,但它是最干净的。 - Dykam
我的物品没有日期... :| - Ms. Nobody

4

如果您想要用新的列表替换原来的列表,您可以尝试以下方法:

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

另一方面,如果你需要stuff保持完全相同的List<T>实例,你可以通过索引对其进行排序,然后删除一个范围:
stuff.Sort(...);
stuff.RemoveRange(0, 3);

3
如果您的列表是有序的,那么您可以简单地使用 RemoveRange 方法:
int n = 3;
stuff.RemoveRange(stuff.Count - n, n);

3
应该先进行排序,然后再删除最后三个。 - Anwar Chandra

1
const int cToRemove = 3;

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

1

到目前为止,所有其他答案都依赖于对列表进行排序,如果您没有对其进行排序,则这是一个O(n log n)操作。

这里有一个解决方案,它是O(n),尽管常数因子很可怕。它使用MoreLINQ中的MinBy - 如果需要,您可以轻松地在自己的代码中重写它,并直接返回索引而不是值(并使用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);
}

你当然可以更高效地编写代码,在单次遍历列表中找到最旧的三个元素 - 但是代码会变得更加复杂,从而增加出错的机会。即使上述代码在思考它要经过列表6次时缺乏优雅,但在O(n)的时间复杂度下应该能够正常工作 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接