我有一个500.000到1.000.000个MyClass
个实例的列表,其中包含以下属性:
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的实例)。
过滤需要表现良好。
答案 0 :(得分:5)
您可以使用GroupBy
和Select
:
var filtered = list
.GroupBy(mc=>mc.ParentId)
.Select(g=>g.OrderByDescending(mc=>mc.EndDate).First())
.ToList();
答案 1 :(得分:2)
虽然目前接受的答案(@Kobi)是正确的,可能是最简单的解决方案,但它可能不是“最佳”解决方案。
特别是,既然你提到你可能在列表中有很多项目并且解决方案应该运行良好,我想我会检查没有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值的数量)。
答案 2 :(得分:1)
我认为您想要根据解释的原因过滤掉测试版,而不是因为它的名字。以下是您可以用来实现这样的结果:
myClasses.GroupBy(i => i.ParentId)
.Select(i => i.OrderByDescending(i2 => i2.EndDate).First());
答案 3 :(得分:0)
您可以使用List<T>
Linq.Where
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();
答案 4 :(得分:0)
你可以使用它,这个方法可以很好地使用大数组工作:
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();