tags:

views:

284

answers:

5
public static bool AllNodesChecked(TreeNodeCollection nodes)        
{
    foreach (TreeNode node in nodes)
    {
        if (!node.Checked)
        {
            return false;
        }
        AllNodesChecked(node.Nodes);
    }
    return true;
}

Test tree is

A1(checked) -> B1(unchecked)
A2(checked)
A3(checked)

but it isn't returning when it hits node B1.

EDIT: Thank you all for helping my tired brain. Recursion should only be attempted early in the day after a cold shower.

+21  A: 

You are ignoring the return value of AllNodesChecked in the recursive call:

public static bool AllNodesChecked(TreeNodeCollection nodes)        
{
    foreach (TreeNode node in nodes)
        if (!node.Checked || !AllNodesChecked(node.Nodes))
           return false;
    return true;
}

The return statement only returns from the current method in the call stack to the immediate caller. It doesn't suddenly return from all other calls above in the call stack.

Mehrdad Afshari
Doh - thank you!
IainMH
+1 for not comparing a boolean to a literal!
Josh Stodola
Yes I noticed that too. I blame it on the fact it isn't called IsChecked like it should be. :-)
IainMH
+7  A: 

Change:

AllNodesChecked(node.Nodes); 

To:

if(!AllNodesChecked(node.Nodes))
    return false;
klausbyskov
+2  A: 

Try this:

public static bool AllNodesChecked(TreeNodeCollection nodes)         
{ 
    foreach (TreeNode node in nodes) 
    { 
        if (node.Checked == false || !AllNodesChecked(node.Nodes)) 
        { 
            return false; 
        } 
    } 
    return true; 
} 
David Gladfelter
+3  A: 

You're not evaluating the result of the recursive call to check child nodes.

markalex
+7  A: 

I would take a slightly different approach here. What I'd do is I'd first write code that turns your tree (which I assume really is a tree, not an arbitrary graph) into a sequence of nodes. Something like:

static IEnumerable<Node> AllNodes(this Node node)
{
    var stack = new Stack<Node>();
    stack.Push(node);
    while(stack.Count > 0)
    {
        var current = stack.Pop();
        yield return current;
        foreach(var child in current.Nodes)
            stack.Push(child);
    }
}

and now you can use sequence operators:

bool allChecked = root.AllNodes().All(x=>x.Checked);

No recursion, no problem.

Eric Lippert
I think recursion is the more natural and readable way to solve these kind of "tree" problems (unless the tree is expected to be larger than the call stack can accommodate).
Mehrdad Afshari
Thanks Eric! However still on 2.0 at work. I know you can hack extension methods but don't want to risk it.
IainMH
@Mehrdad: I agree, it is more elegant to use recursion on a recursive data structure. However, (1) lack of tail recursion, (2) catastrophic failure when stack is blown, (3) recursive iterator blocks are inefficient, (4) sequence operators rock. These points push me towards iterative solutions that reinterpret recursive data structures as unstructured sequences.
Eric Lippert
@Eric: Totally agree with (4)! Agree with (3). (2) may not be the case in many cases where the data structure is supposed to be very small and it's kind of an "optimization", but definitely true if it can be large. The main point, (1), what are you guys going to do about it? ;) Are we ever going to see these F# fans harassing us for the lack of tail recursion in the C# compiler itself go away?
Mehrdad Afshari
@Mehrdad - just to rub it in, I believe that F# also solves point 3, in that the `yield!` operator does what a hypothetical `yield foreach` would do in C#.
kvb
@Mehrdad: the trouble is that the tailcall instruction leads to code which adds cost at runtime. Fortunately, the 64 bit jitter is now pretty smart about generating tail calls when jitting the code even if the IL doesn't require it. The 32 bit jitter is apparently not there yet though. I'd like to see this happen, but regrettably it is not a high priority.
Eric Lippert