使用 LINQ 我有一个列表列表,如何 select 每个列表中存在的所有对象?
Using LINQ I have a list of lists, how do I select all objects that exist in every list?
我有一个列表列表:
List<Tuple<string, List<SomeObject>>
我想要 select 上面列表所有行中存在的所有 SomeObjects
。
有些只存在于一个或两个列表中,但我希望所有对象都存在于每个列表中,而其他对象则被丢弃。
如果没有一堆 c# 代码,我无法找到一个优雅的解决方案。有什么好的方法吗?
假设 class 覆盖 Equals
+ GetHashCode
或者您有自定义 IEqualityComparer<SomeObject>
您可以使用以下使用 Enumerable.All
的查询:
var result = list
.SelectMany(t => t.Item2) // select all objects
.Distinct() // just an optimization since duplicates are guaranteed
.Where(obj => list.All(t => t.Item2.Contains(obj)));
这是我的示例数据:
var list = new List<Tuple<string, List<SomeObject>>>();
list.Add(Tuple.Create("a", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 4 } }));
list.Add(Tuple.Create("b", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 3 } }));
list.Add(Tuple.Create("c", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 3 } }));
list.Add(Tuple.Create("d", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 3 } }));
只有 ID = 1 或 ID = 2 的 SomeObjects
在所有列表中,这是查询的结果。
据我了解,您需要多个列表的交集:
var results = source.First().Item2
foreach (var element in source.Skip(1) )
{
results = results.Intersect(element.Item2)
}
list.Select (x => x.Item2 as IEnumerable<SomeObject>)
.Aggregate((x,y)=> x.Intersect(y))
.ToList();
或者,正如 Jeppe Stig Nielsen 所建议的(我认为它更优雅):
list.Select(x => x.Item2.AsEnumerable())
.Aggregate(Enumerable.Intersect)
.ToList();
受到 Juan Lopes 漂亮答案的强烈启发,您可以定义此扩展:
static IEnumerable<TSource> IntersectMany<TSource>(this IEnumerable<IEnumerable<TSource>> sources)
{
return sources.Aggregate(Enumerable.Intersect);
}
然后这有效:
var result = list.Select(x => x.Item2).IntersectMany();
之所以有效,是因为 IEnumerable<out T>
在 T
(C# 4、.NET 4.0)中是协变的。
我有一个列表列表:
List<Tuple<string, List<SomeObject>>
我想要 select 上面列表所有行中存在的所有 SomeObjects
。
有些只存在于一个或两个列表中,但我希望所有对象都存在于每个列表中,而其他对象则被丢弃。
如果没有一堆 c# 代码,我无法找到一个优雅的解决方案。有什么好的方法吗?
假设 class 覆盖 Equals
+ GetHashCode
或者您有自定义 IEqualityComparer<SomeObject>
您可以使用以下使用 Enumerable.All
的查询:
var result = list
.SelectMany(t => t.Item2) // select all objects
.Distinct() // just an optimization since duplicates are guaranteed
.Where(obj => list.All(t => t.Item2.Contains(obj)));
这是我的示例数据:
var list = new List<Tuple<string, List<SomeObject>>>();
list.Add(Tuple.Create("a", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 4 } }));
list.Add(Tuple.Create("b", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 3 } }));
list.Add(Tuple.Create("c", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 3 } }));
list.Add(Tuple.Create("d", new List<SomeObject> { new SomeObject { ID = 1 }, new SomeObject { ID = 2 }, new SomeObject { ID = 3 } }));
只有 ID = 1 或 ID = 2 的 SomeObjects
在所有列表中,这是查询的结果。
据我了解,您需要多个列表的交集:
var results = source.First().Item2
foreach (var element in source.Skip(1) )
{
results = results.Intersect(element.Item2)
}
list.Select (x => x.Item2 as IEnumerable<SomeObject>)
.Aggregate((x,y)=> x.Intersect(y))
.ToList();
或者,正如 Jeppe Stig Nielsen 所建议的(我认为它更优雅):
list.Select(x => x.Item2.AsEnumerable())
.Aggregate(Enumerable.Intersect)
.ToList();
受到 Juan Lopes 漂亮答案的强烈启发,您可以定义此扩展:
static IEnumerable<TSource> IntersectMany<TSource>(this IEnumerable<IEnumerable<TSource>> sources)
{
return sources.Aggregate(Enumerable.Intersect);
}
然后这有效:
var result = list.Select(x => x.Item2).IntersectMany();
之所以有效,是因为 IEnumerable<out T>
在 T
(C# 4、.NET 4.0)中是协变的。