假设我有一个对象:
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 :(得分:8)
如果您只需要枚举这些项目,这将有效:
stuff.OrderBy(item => item.Date).Skip(3);
如果您确实需要列表形式,则必须在之后致电.ToList()
:
stuff = stuff.OrderBy(item => item.Date).Skip(3).ToList();
答案 1 :(得分:4)
如果您愿意用新的列表替换列表,可以试试这个:
stuff = stuff.OrderBy( c => c.Date).Skip(3).ToList();
另一方面,如果您需要stuff
保持完全相同的List<T>
实例,则可以对其进行排序,然后按索引删除范围:
stuff.Sort(...);
stuff.RemoveRange(0, 3);
答案 2 :(得分:3)
如果您的列表已订购,则只需使用RemoveRange
方法:
int n = 3;
stuff.RemoveRange(stuff.Count - n, n);
答案 3 :(得分:1)
const int cToRemove = 3;
var top3 = (from c in stuff
orderby c.Date ascending
select c).Take(cToRemove);
答案 4 :(得分:1)
到目前为止,所有其他答案都依赖于对列表进行排序,如果您尚未对其进行排序,则该操作是O(n log n)操作。
这是一个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次列表时也缺乏优雅:)