Вы не сможете сделать что-то подобное только с одним LINQ;LINQ не имеет поддержки для обхода неизвестного уровня узлов из коробки.
Кроме того, у вас нет реального способа уплощения структуры, количества требуемых свойствнеизвестно (поскольку оно связано с глубиной дерева, что также неизвестно).
Я бы порекомендовал использовать итераторы в C # , чтобы сгладить дерево, что-то вроде этого:
static IEnumerable<T> Flatten(this IEnumerable<T> source,
Func<T, IEnumerable<T>> childrenSelector)
{
// Do standard error checking here.
// Cycle through all of the items.
foreach (T item in source)
{
// Yield the item.
yield return item;
// Yield all of the children.
foreach (T child in childrenSelector(item).
Flatten(childrenSelector))
{
// Yield the item.
yield return child;
}
}
}
Затем вы можете вызвать метод расширения и поместить результаты в List<T>
;он примерно такой же плоский, как вы собираетесь получить.
Обратите внимание, вы можете очень легко бросить StackOverflowException
, если иерархия достаточно глубока.Для этого вам действительно нужно использовать этот нерекурсивный метод:
static IEnumerable<T> Flatten(this IEnumerable<T> source,
Func<T, IEnumerable<T>> childSelector)
{
// Do standard error checking here.
// Create a stack for recursion. Push all of the items
// onto the stack.
var stack = new Stack<T>(source);
// While there are items on the stack.
while (stack.Count > 0)
{
// Pop the item.
T item = stack.Pop();
// Yield the item.
yield return item;
// Push all of the children on the stack.
foreach (T child in childSelector(item)) stack.Push(child);
}
}
Экземпляр Stack<T>
живет в куче, а не в стеке вызовов, поэтому выне будет исчерпано пространство стека вызовов.
Кроме того, вы можете изменить Stack<T>
на Queue<T>
, если вы хотите использовать другую семантику возврата (или вы можете просматривать дочерние элементы вдругими способами), если вам требуется определенный заказ.
Если вам нужен очень конкретный заказ, я бы рекомендовал изменить порядок в методе, только если у вас есть большое количество элементов, которые необходимо просмотреть, что делаетвызов OrderBy
на возвращаемое значение непозволительно.