从列表中删除项目的最佳方法

Best method to remove items from a list

我有一个 MyClass 的 500.000 到 1.000.000 个实例的列表,它具有以下属性:

class MyClass
{
    string ParentId;
    string Name;
    DateTime StartDate;
    DateTime EndDate;
}

数据可能如下所示:

ParentId | Name    | StartDate    | EndDate
----------------------------------------------
parent1  | alpha   | 01-01-2011   | 02-02-2015
parent1  | beta    | 01-01-2011   | 02-02-2014
parent2  | gamma   | 01-01-2012   | 02-02-2011

我需要过滤列表,使其包含 "alpha" 和 "gamma" 对象。 "beta" 对象应排除在外,因为它与 alpha 具有相同的父对象,但 EndDate 更早。

即结果列表应该只包含每个 ParentId 的一个实例(具有最新 EndDate 的实例)。

过滤需要良好的表现。

您可以使用 Linq.Where

轻松过滤 List<T>
var result = myList
    .Where(item => item.Name == "gamma" || item.Name == "alfa")
    .ToList();

如果你想区分某个字段的输出,你可以使用MoreLinq's DistinctBy

GroupBy:

var result = myList
    .Where(item => item.Name == "gamma" || item.Name == "alfa")
    .GroupBy(item => item.ParentId)
    .Select(g => g.First()) //Selection logic
    .ToList();

您可以使用 GroupBySelect:

var filtered = list
              .GroupBy(mc=>mc.ParentId)
              .Select(g=>g.OrderByDescending(mc=>mc.EndDate).First())
              .ToList();

我假设您想过滤掉 beta 是出于解释的原因,而不是因为它的裸名。您可以使用以下方法来获得这样的结果:

myClasses.GroupBy(i => i.ParentId)
    .Select(i => i.OrderByDescending(i2 => i2.EndDate).First());

你可以使用它,这个方法对大数组工作得很好而且很快:

var groupesList = yourList.GroupBy(x => x.ParentId,
     (y, set) => new {Key = y, Value = set.First(s => s.EndDate == set.Max(r => r.EndDate))}).Select(x => x.Value).ToList();

虽然目前接受的答案(来自@Kobi)是正确的并且可能是最简单的解决方案,但它可能不是 "best" 解决方案。

特别是,由于您提到列表中可能有很多项目并且解决方案应该表现良好,我想我会检查没有 LINQ 的解决方案如何执行。

这是我的解决方案:

var tempDict = new Dictionary<string, MyClass>();
foreach (var data in list) // list is the List<MyClass>
{
    MyClass existing;
    if (!tempDict.TryGetValue(data.ParentId, out existing))
    {
        // Put item into temp dictionary (use ParentId as key)
        tempDict[data.ParentId] = data;
    }
    else
    {
        // Check if the instance in the temp dictionary has an
        // earlier EndDate. If yes, replace it.
        if (existing.EndDate < data.EndDate) // replace
            tempDict[data.ParentId] = data;
    }
}

var result = tempDict.Values.ToList();

快速比较(使用 500.000 个项目)显示此解决方案比 LINQ 版本快大约 3 到 4 倍(取决于唯一 ParentId 值的数量)。