使用LINQ,您将如何从列表中过滤出特定条件的所有项目,仅保留一个项目
本文关键字:项目 保留 一个 LINQ 使用 过滤 列表 特定条件 | 更新日期: 2023-09-27 18:15:03
我意识到我的标题可能不是很清楚所以这里有一个例子:
我有一个对象列表,它有两个属性,a和b。
public class Item
{
public int A { get; set; }
public int B { get; set; }
}
var list = new List<Item>
{
new Item() { A = 0, B = 0 },
new Item() { A = 0, B = 1 },
new Item() { A = 1, B = 0 },
new Item() { A = 2, B = 0 },
new Item() { A = 2, B = 1 },
new Item() { A = 2, B = 2 },
new Item() { A = 3, B = 0 },
new Item() { A = 3, B = 1 },
}
使用LINQ,将所有A = 2项折叠成第一个A = 2项并与所有其他项一起返回的最优雅的方法是什么?这将是预期的结果。
var list = new List<Item>
{
new Item() { A = 0, B = 0 },
new Item() { A = 0, B = 1 },
new Item() { A = 1, B = 0 },
new Item() { A = 2, B = 0 },
new Item() { A = 3, B = 0 },
new Item() { A = 3, B = 1 },
}
我不是一个LINQ专家,已经有一个"手动"的解决方案,但我真的很喜欢LINQ的表现力,并很好奇,看看它是否可以做得更好。
如何:
var collapsed = list.GroupBy(i => i.A)
.SelectMany(g => g.Key == 2 ? g.Take(1) : g);
我们的想法是首先通过A
对它们进行分组,然后再次选择它们(用.SelectMany
将其扁平化),但在Key
是我们想要崩溃的情况下,我们只需使用Take(1)
的第一个条目。
您可以使用GroupBy
来完成此任务。按A
对项目进行分组,并使用SelectMany
将每组再次投影到平面列表中。在SelectMany
中,检查A
是否为2
,如果为Take(1)
,否则返回该组的所有结果。我们使用Take
而不是First
,因为结果必须是IEnumerable
。
var grouped = list.GroupBy(g => g.A);
var collapsed = grouped.SelectMany(g =>
{
if (g.Key == 2)
{
return g.Take(1);
}
return g;
});
一个可能的解决方案(如果您坚持使用LINQ):
int a = 2;
var output = list.GroupBy(o => o.A == a ? a.ToString() : Guid.NewGuid().ToString())
.Select(g => g.First())
.ToList();
将所有具有A=2
的项目分组到具有等于2
的键的组中,但所有其他项目将具有唯一的组键(新guid),因此您将有许多拥有一个项目的组。然后从每组中取第一件。
另一种方式:
var newlist = list.Where (l => l.A != 2 ).ToList();
newlist.Add( list.First (l => l.A == 2) );
基于GroupBy
的另一个答案可以是Aggregate
:
// Aggregate lets iterate a sequence and accumulate a result (the first arg)
var list2 = list.Aggregate(new List<Item>(), (result, next) => {
// This will add the item in the source sequence either
// if A != 2 or, if it's A == 2, it will check that there's no A == 2
// already in the resulting sequence!
if(next.A != 2 || !result.Any(item => item.A == 2)) result.Add(next);
return result;
});
这个呢:
list.RemoveAll(l => l.A == 2 && l != list.FirstOrDefault(i => i.A == 2));
如果你想要更有效的方式,它将是:
var first = list.FirstOrDefault(i => i.A == 2);
list.RemoveAll(l => l.A == 2 && l != first);