繁体   English   中英

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

[英]Remove 3 oldest elements from a List<> in 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 => ???)

如果您只需要枚举项目,这将有效:

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

如果你真的想要它以列表形式,你将不得不调用.ToList()之后:

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

如果您愿意用新的列表替换列表,可以尝试这样做:

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

另一方面,如果您需要的stuff保持相同的List<T>实例,您可以对其进行排序,然后按索引删除范围:

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

如果您的列表是订购的,您只需使用RemoveRange方法:

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);

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

这是一个O(n)的解决方案,尽管它具有可怕的常数因子。 它使用MinByMinBy - 如果需要,您可以在自己的代码中轻松地重写它,甚至使它直接返回索引而不是值(并使用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次时缺乏优雅:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM