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

时间:2012-01-16 22:10:01

标签: c# .net linq linq-to-objects

我有一个具有List属性的类,我将这个类命名为A.然后我有一个List<A>

我需要LINQ for objects来获取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>个对象中唯一包含的对象。

4 个答案:

答案 0 :(得分:10)

如果您有一个列表列表,并且您想要所有内部列表中的元素,则可以使用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);

答案 1 :(得分:4)

您可以使用Intersect(),前提是至少有一个元素,而您的班级B有足够的平等实施/ GetHashCode()

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

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

答案 2 :(得分:2)

只要为类型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)

答案 3 :(得分:2)

我接近这个的方法是创建一个所有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() );