简体   繁体   中英

C# Intersect beetween multiple objects lists

I have next situation:

public class ParentClass
{
    public string Name { get; set; }

    public List<ChildClass> ChildrenList {get;set;}
}

public class ChildClass
{
    public string Name { get; set; }

    public GrandChildClass GrandChild { get; set; }
}

public class GrandChildClass
{
    public string Name { get; set; }
}

GrandChildClass grandChild1 = new GrandChildClass() { Name = "AAA1" };
GrandChildClass grandChild2 = new GrandChildClass() { Name = "BBB1" };
GrandChildClass grandChild3 = new GrandChildClass() { Name = "CCC1" };
GrandChildClass grandChild4 = new GrandChildClass() { Name = "DDD1" };

ChildClass child1 = new ChildClass() { Name = "AAA", GrandChild = grandChild1 };
ChildClass child2 = new ChildClass() { Name = "BBB", GrandChild = grandChild2 };
ChildClass child3 = new ChildClass() { Name = "CCC", GrandChild = grandChild3 };
ChildClass child4 = new ChildClass() { Name = "DDD", GrandChild = grandChild4 };
ChildClass child5 = new ChildClass() { Name = "EEE", GrandChild = grandChild2 };

List<ParentClass> parentsList = new List<ParentClass>()
{
    new ParentClass { Name = "Parent1", ChildrenList = new List<ChildClass>() { child1, child2 } },
    new ParentClass { Name = "Parent2", ChildrenList = new List<ChildClass>() { child3, child4 } },
    new ParentClass { Name = "Parent3", ChildrenList = new List<ChildClass>() { child1, child5 } }
}

I would like to make the simplest way of finding which parents have mutual children.

I don't want to make some foreach loops and compare like that, but I would like to use linq functions such is Intersect or some similar.

For example here is a similar thing, that is working:

List<List<string>> lists = new List<List<string>>()
{
    new List<string> {"Hello", "World", "7"},
    new List<string> {"Hello", "7", "Person"},
    new List<string> {"7", "7", "Hello"}
};

List<string> extList = lists.Cast<IEnumerable<string>>()
                .Aggregate((a, b) => a.Intersect(b)).ToList();

In my case I would like the result to be: Parent1 and Parent3 have child1 in common.

Any idea?

EDIT:

Additionally, how to find all parents that have mutual grandchildren?

You are looking for something like:

var results = parentsList
  .SelectMany(parent => parent.ChildrenList)
  .Distinct()
  .Select(child => new 
          { 
              Child = child, 
              Parents = parentsList.Where(parent => parent.ChildrenList.Contains(child)) 
          });

You need to flatten the ChildrenLists and distinct them. Next you should select the child and all the parents who has this child in their ChildrenList.

I've named the parents for more usefull results:

AAA => X, Z
BBB => X
CCC => Y
DDD => Y
EEE => Z

In my case it says, This child has these parents.

You can group by child and then select groups with multiple parents:

var result = parentsList.SelectMany(p => p.ChildrenList.Select(c => (child: c, parent: p)))
    .GroupBy(c => c.child, c => c.parent)
    .Where(g => g.Count() > 1);

I've modified your input and add Name property to Parent class:

List<ParentClass> parentsList = new List<ParentClass>()
{
    new ParentClass { Name = "p1", ChildrenList = new List<ChildClass>() { child1, child2 } },
    new ParentClass { Name = "p2", ChildrenList = new List<ChildClass>() { child3, child4 } },
    new ParentClass { Name = "p3", ChildrenList = new List<ChildClass>() { child1, child5 } }
};

Next code

foreach (var child in result)
    Console.WriteLine(String.Join(", ", child.Select(p => p.Name)));

Will print

p1, p3

You could find all child with the same reference with the next code:

List<ChildClass> result = parentsList.SelectMany(x => x.ChildrenList)
.GroupBy(x => x).Where( x=> x.Count() > 1)
.SelectMany(x => x).Distinct().ToList() ;

BTW your code is working due to encountering "Hello" in each child list, skips it in second list and result List would be empty:

List extList = lists.Cast>() .Aggregate((a, b) => a.Intersect(b)).ToList();

To find mutual Children for Parents I use:

var results = parentsList
    .SelectMany(p => p.ChildrenList)
    .Distinct()
    .Select(child => new
    {
        Child = child,
        Parents = parentsList.Where(p => p.ChildrenList.Contains(child)).ToList()
    }).ToList();

To find mutual GrandChildren for Parents I use:

var results = parentsList
    .SelectMany(p => p.ChildrenList)
    .Distinct()
    .Select(child => new
    {
        child.GrandChild,
        Parent = parentsList.Where(p => p.ChildrenList.Any(c => c.GrandChild == child.GrandChild)).ToList()
    }).GroupBy(c => c.GrandChild)
    .Select(group => group.First());

Thanks to Jeroen van Langen for the answer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM