C # Пересечение между несколькими списками объектов - PullRequest
4 голосов
/ 23 мая 2019

У меня следующая ситуация:

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 } }
}

Я бы хотел найти самый простой способ выяснить, у каких родителей есть общие дети.

Я не хочу создавать циклы foreach и сравнивать их, но я хотел бы использовать функции linq, такие как Intersect или некоторые другие.

Например, вот похожая вещь, которая работает:

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();

В моем случае я бы хотел, чтобы результат был: Parent1 и Parent3 имеют общего child1.

Есть идеи?

EDIT:

Кроме того, как найти всех родителей, у которых есть общие внуки?

Ответы [ 4 ]

2 голосов
/ 23 мая 2019

Вы можете группировать по детям, а затем выбирать группы с несколькими родителями:

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);

Я изменил ваш ввод и добавил свойство Name в родительский класс:

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 } }
};

Следующий код

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

Распечатает

p1, p3

2 голосов
/ 23 мая 2019

Вы ищете что-то вроде:

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

Вам нужно сгладить списки детей и выделить их.Затем вы должны выбрать ребенка и всех родителей, у которых этот ребенок есть в их списке детей.

Я назвал родителей для более полезных результатов:

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

В моем случае говорится:У этого ребенка есть эти родители.

0 голосов
/ 24 мая 2019

Чтобы найти общих детей для родителей, я использую:

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

Чтобы найти общих детей для родителей, я использую:

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());

Благодарю Йероена ван Ланген за ответ.

0 голосов
/ 23 мая 2019

Вы можете найти всех дочерних элементов с одинаковыми ссылками со следующим кодом:

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

Кстати, ваш код работает из-за того, что встречается «Hello» в каждом дочернем списке, пропускает его во втором списке и списке результатов.будет пустым:

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

...