You can use following extension method for flattening hierarchy (see alternative flattening algorithm in answer update below):
public static IEnumerable<T> Flatten<T>(
this IEnumerable<T> source, Func<T, IEnumerable<T>> childrenSelector)
{
foreach (var item in source)
{
yield return item;
var children = childrenSelector(item);
if (children == null)
continue;
foreach (var child in children.Flatten(childrenSelector))
yield return child;
}
}
I takes child selector and recursively yields children. Then projection is simple:
var result = nodes.Flatten(n => n.Children).Select(n => n.Id);
Assume you have following Node class:
public class Node
{
public Node(int id, params Node[] children)
{
Id = id;
if (children.Any())
Children = new List<Node>(children);
}
public int Id { get; set; }
public List<Node> Children { get; set; }
}
Then with your sample hierarchy:
List<Node> nodes = new List<Node> {
new Node(1),
new Node(2, new Node(3)),
new Node(4, new Node(5),
new Node(6, new Node(7)))
};
Output will be:
1, 2, 3, 4, 5, 6, 7
UPDATE: You can flatten hierarchy without usage of recursion (for better performance):
public static IEnumerable<T> Flatten<T>(
this IEnumerable<T> source, Func<T, IEnumerable<T>> childrenSelector)
{
Queue<T> queue = new Queue<T>();
foreach (var item in source)
queue.Enqueue(item);
while (queue.Any())
{
T item = queue.Dequeue();
yield return item;
var children = childrenSelector(item);
if (children == null)
continue;
foreach (var child in children)
queue.Enqueue(child);
}
}