views:

464

answers:

4

Hi,

I need to write a tree search method which takes a type parameter T and returns all items of type T that exist in the tree. Is there any way to do this? I would prefer elegance over efficiency at this point...

+1  A: 

Assuming your tree is generic. i.e. Item<T>.

int count = yourTree.Count(p => p == typeof(T));

Otherwise, parse each node and compare "item == typeof(T)"

Dead account
+2  A: 

Well, internally the method would have to iterate over all the elements of the tree, so the skip to just enumerating over it, and using the OfType LINQ method isn't that far:

var onlyTs = yourTree.OfType<SomeT>();
Lasse V. Karlsen
+1 for giving the correct answer :) Just realised I missed the point
Dead account
+1  A: 

What you need is a basic tree traversal function (preorder, inorder or postorder -- this doesn't matter) and a filter function. Then you can compose those two together and get what you need:

IEnumerable<T> Traverse(Tree<T> tree)
{
    yield return tree.Data;

    foreach(Tree<T> subtree in tree.Subtrees)
        foreach(T t in Traverse(subtree))
            yield return t;
}

IEnumerable<U> Filter<T, U>(IEnumerable<T> source)        
    where U : T
{
    foreach(T t in source)
        if(t is U)
            yield return (U)t;
}
Anton Gogolev
Similar idea to mine, but I'd make one change: you're doing the conversion twice - `t as U` and checking for null is quicker for classes than `if( t is U ) (U) t`;
Keith
+2  A: 

Something like this:

internal static IEnumerable<T> AllDescendantNodes<T>( this TreeNode input ) 
    where T class;
{
    T current = null;
    foreach ( TreeNode node in input.Nodes )
        if( (current = node as T) != null )
        {
            yield return current;
            foreach ( var subnode in node.AllDescendantNodes<T>() )
                yield return subnode;
        }
}

You would then call this against the root node as an extension method:

foreach( MyCustomNodeClass item in rootNode.AllDescendantNodes<MyCustomNodeClass>() ) 
{
    ...
}
Keith
That works for me. I have no understanding yet of extension methods, so unsure as to whether it is performant. But it is an elegant solution. From what I see only the descendents of a given input are checked. I had to modify AllDescendants to check for the input node type and yield it. Thanks
Actually, I needed to create a special root node, then pass that in. Modifying AllDescendants was wrong. Thanks
Extension methods are converted at compile time to normal static calls - there's no performance implication for using them. This method handles the recursion, so I'd potentially have a similar one that worked on the tree's root nodes and then called this.
Keith