-2

I have a foreach method like this:

 TreeNode selectedNode = null;

 foreach (TreeNode tn in allNodes)
                {
                    if (selectedNode != null) continue;
                    var designNodes = tn.Nodes;


                    foreach (TreeNode item in designNodes)
                    {
                        if (item.Tag.ToString().Split('|')[0].Equals(designKey.ToString()))
                        {
                            selectedNode = item;
                            continue;
                        };
                        if (selectedNode is null)
                        {
                            foreach (TreeNode child in item.Nodes)
                            {
                                if (child.Tag != null && child.Tag.ToString().Split('|')[0].Equals(designKey.ToString()))
                                {
                                    selectedNode = child;
                                    continue;
                                }
                                if (selectedNode is null)
                                {
                                    foreach (TreeNode lastLevel in child.Nodes)
                                    {
                                        if (lastLevel.Tag != null && lastLevel.Tag.ToString().Split('|')[0].Equals(designKey.ToString()))
                                        {
                                            selectedNode = lastLevel;
                                            continue;
                                        }
                                    }
                                }

                            }

                        }

                    }
                }   

First it iterates into TreeNode parent and assign variable selectedNode, if it does not found results (selectedNode still null) it look childs of parent, and if it still null it look at childs of child.

Code it's working but it's too dificult to read, there is a best way to implement this iteration?

Jonathan
  • 601
  • 9
  • 26
  • `if (selectedNode is null)` should be `if (selectedNode == null)` – Rufus L Mar 13 '19 at 19:58
  • Sorry, I update my question @RufusL – Jonathan Mar 13 '19 at 20:01
  • 1
    Shouldn't the `continue;` lines be `break;` instead? It seems like those are where you've found the correct match. Why continue? Also, is the purpose here to find the first node that meets the `Tag == designKey` condition? Or something else? – Rufus L Mar 13 '19 at 20:06
  • Yes if it assign lastDesign variable I use continue to break and it should finish assignation @RufusL – Jonathan Mar 13 '19 at 20:09
  • `continue` doesn't break, though...it just skips the rest of that iteration and then continues the loop. `break` will break out of the loop. Can you please define specifically what the code is supposed to do? – Rufus L Mar 13 '19 at 20:11

1 Answers1

0

It sounds like what you're looking for here is a breadth-first search, where you first search all the children, then each child's children, etc, until you find a match.

For this type of searching we want to use a Queue, which is "first in - first out" (as opposed to a stack, which is "last in - first out"). This way we can Enqueue the root TreeNode items into the queue, then in a loop we Dequeue each item one at a time, check if it's valid, return it if it is, and if it isn't we Enqueue it's children. This ensures that we always check the parents before the children.

I've made this method a little more flexible as well by allowing the client to pass in a validator function that will be used to validate a TreeNode. This way we can re-use the method for doing breadth-first searching on any criteria we wish (we just pass to it a method that takes in a TreeNode and returns a bool that is true if the validation succeeds for that node):

private static TreeNode GetFirstMatch(TreeNodeCollection allNodes, 
    Func<TreeNode, bool> validator)
{
    if (allNodes == null) return null;

    // Initialize a Queue with all the root nodes
    var nodeQueue = new Queue<TreeNode>(allNodes.OfType<TreeNode>());

    // Use a queue for a breadth-first search
    while (nodeQueue.Any())
    {
        // Remove the next item
        var current = nodeQueue.Dequeue();

        // Return it if it passes our validation
        if (validator.Invoke(current)) return current;

        // Add it's children to the end of the queue
        foreach (TreeNode child in current.Nodes)
        {
            nodeQueue.Enqueue(child);
        }
    }

    // If we didn't find any matches, return null
    return null;
}

In use we can just pass the Nodes property of our TreeView control to the method, along with the validation function (in this example I'm passing a lambda expression for the validation function):

TreeNode firstMatch = GetFirstMatch(treeView1.Nodes,
    node => node.Tag.ToString().Split('|')[0].Equals(designKey.ToString()));
Rufus L
  • 36,127
  • 5
  • 30
  • 43