Linq查询以获取子列表中的共享项

本文关键字:共享 列表 查询 获取 Linq | 更新日期: 2023-09-27 18:20:41

我有一个类,它的属性是List,我将把这个类命名为a。然后我有了一个List<A>

我需要对象的LINQ来获取List<A>上所有项目上存在的所有对象B。

需要澄清的示例:

var list = new List<A>
           {
             new A { B = new List<B> { B1, B2, B3, B4 } }
             new A { B = new List<B> { B3, B4, B5, B6 } }
             new A { B = new List<B> { B2, B3, B4, B5, B6 } }
           };

查询必须返回对象B3和B4,因为它们是所有List<A>对象中唯一包含的对象。

Linq查询以获取子列表中的共享项

如果你有一个列表列表,并且你想要所有内部列表中的元素,你可以使用AggregateIntersect的组合,如下所示:

IEnumerable<IEnumerable<string>> listOfLists = new string[][] {
    new string[] { "B1", "B2", "B3", "B4" },
    new string[] { "B3", "B4", "B5", "B6" },
    new string[] { "B2", "B3", "B4", "B5", "B6" }
};
IEnumerable<string> commonElements = listOfLists.Aggregate(Enumerable.Intersect);

只要至少有一个元素,并且类B具有等式/GetHashCode():的充分实现,就可以使用Intersect()

IEnumerable<B> allBs = list[0].B;
foreach (var item in list.Skip(1))
{
    allBs = allBs.Intersect(item.B);
}

除了增加复杂性之外,我认为"纯"Linq解决方案没有任何好处。

只要为类型B的对象正确定义了Equals/GetHashCode,那么这实际上有点简单:

_listToQuery.Aggregate(
    _listToQuery.First().B, 
    (seed, nextItem) => { seed = seed.Intersect(nextItem.B); return seed; })

或者,另一种方式:

_listToQuery.SelectMany(tr => tr.B)
    .GroupBy(tr => tr)
    .Where(tr => tr.Count() == _listToQuery.Count)
    .Select(tr => tr.Key)

我处理这一问题的方法是创建一个所有B的列表,然后通过某个唯一标识符(如果它们是可比较的,则仅为对象)对它们进行分组,找出哪些B不止一次出现。分组后,选择实例数大于1的实例,使用每个分组的第一个实例作为规范代表。

var selection = list.SelectMany( a => a.B )
                    .GroupBy( b => b.UniqueID, b => b )
                    .Where( b => b.Count() > 1 )
                    .Select( b => b.First() );