LINQ: как преобразовать вложенный иерархический объект в плоскость объекта
Как преобразовать вложенный иерархический объект для выравнивания объектов с помощью LINQ? Я знаю, что мы можем легко использовать foreach loop для достижения этого. Но мне интересно, есть ли способ записать его в LINQ.
class Person{
public int ID {get;set}
public string Name {get;set}
public List<Person> Children {get;}
}
Данные:
ID : 1
Name : Jack
Children
2 | Rose
3 | Paul
Мне нравится преобразовывать эти данные в формат сглаживания, как показано ниже.
1 | Jack
2 | Rose
3 | Paul
Как мы можем это сделать с Linq?
Ответы
Ответ 1
Если вы хотите, чтобы он сглаживал произвольно глубокое дерево людей, я предлагаю следующее:
public IEnumerable<Person> GetFamily(Person parent)
{
yield return parent;
foreach (Person child in parent.Children) // check null if you must
foreach (Person relative in GetFamily(child))
yield return relative;
}
На самом деле нет хорошего способа сократить это с помощью LINQ, потому что анонимные лямбды не могут называть себя рекурсивно, не реализуя Y. Вы можете "уменьшить" вышеупомянутый метод до
return parent.Children.SelectMany(p => GetFamily(p))
.Concat(new Person[] { parent });
или, альтернативно,
yield return parent;
foreach (Person relative in parent.Children.SelectMany(GetFamily))
yield return relative;
но это кажется мне ненужным.
Ответ 2
Это хороший, универсальный и многоразовый метод расширения:
static public IEnumerable<T> Descendants<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> descendBy)
{
if (!source.IsNullOrEmpty())
{
foreach (T value in source)
{
yield return value;
if (!descendBy(value).IsNullOrEmpty())
{
foreach (T child in descendBy(value).Descendants<T>(descendBy))
{
yield return child;
}
}
}
}
}
В приведенном выше примере используйте следующее:
var allChildren = parent.Children.Descendants(p => p.Children);
Один незначительный nit состоит в том, что он не включает исходный родительский список в списке, вам нужно это сделать.