2

How can I get a List from all nodes in a tree using LINQ?

My classes are:

class Node
{
 public class Node()
 {
  Children = new List<Node>();
 }

 public List<Node> Children { get; set;}
}

class Tree
{
 public Tree()
 {
  Roots = new List<Node>();
 }

 List<Node> Roots { get; set;}
}
Bobby
  • 11,419
  • 5
  • 44
  • 69
Homam
  • 23,263
  • 32
  • 111
  • 187
  • No, it is not, I've a tree of objects and I need to do some queries on it, that's it – Homam Aug 11 '10 at 12:57
  • Start on [Eric Lippert's](http://stackoverflow.com/users/88656/eric-lippert "Eric Lippert's") blog from the link below: http://blogs.msdn.com/b/ericlippert/archive/2010/04/19/every-binary-tree-there-is.aspx This might be a more general discussion than you're looking for, but it will answer your question and a lot more besides... – mavnn Aug 11 '10 at 14:02

3 Answers3

3
class Node
    {
    public Node()
    {
        Children = new List<Node>();
    }

    public IEnumerable<Node> GetSubTree()
    {
        return Children.SelectMany(c => c.GetSubTree()).Concat(new[] { this });
        //Post-order traversal
    }

    public List<Node> Children { get; set; }
}

class Tree
{
    public Tree()
    {
        Roots = new List<Node>();
    }

    public IEnumerable<Node> GetAllNodes()
    {
        return Roots.SelectMany(root => root.GetSubTree());
    }

    List<Node> Roots { get; set; }
}

How can a tree have more than one root though? Isn't this a forest?

Ani
  • 111,048
  • 26
  • 262
  • 307
  • @Homan Func> nodesForTree = tree => tree.GetAllNodes(); Is that what you want? Why though? – Ani Aug 11 '10 at 13:10
  • Thank you for your response, I'll use your code, I was want to make a query without changing the class body, in other words, create the function GetSubTree before the query and use it in the query without changing the class. anyway, thank you again :) – Homam Aug 11 '10 at 22:03
  • @ Homan: I understand. If that is what your requirement, you could easily put these methods in a separate class, since they only require access to public properties. You could mark them as extension methods to simpify usage syntax. – Ani Aug 12 '10 at 15:58
3
var allNodes = yourTree.Roots.SelectMany(x => x.TraverseTree(y => y.Children));

// ...

public static class EnumerableExtensions
{
    public static IEnumerable<T> TraverseTree<T>(
        this T parentNode, Func<T, IEnumerable<T>> childNodesSelector)
    {
        yield return parentNode;

        IEnumerable<T> childNodes = childNodesSelector(parentNode);
        if (childNodes != null)
        {
            foreach (T childNode in
                childNodes.SelectMany(x => x.TraverseTree(childNodesSelector)))
            {
                yield return childNode;
            }
        }
    } 
}
LukeH
  • 263,068
  • 57
  • 365
  • 409
1

You can do this by either adding a traversal method, or by using recursive LINQ with Y-combinator. I personally prefer first approach.

Anton Gogolev
  • 113,561
  • 39
  • 200
  • 288