Home > Back-end >  Tree view control, get next available node name from the max value
Tree view control, get next available node name from the max value

Time:10-13

I'm working on a method that gives the next available node name if a node with the specified name exists. But the idea is that the method gives the next one from the max value, for example:

enter image description here

If I add a new node called "test", the method should return "test6" and not "test2". The same happens with the nodes that contain numbers as names:

enter image description here

If I add a new node with the name "20", the next available name should be "31".

So the idea is to get the "max value" from a sequence and add one to it. This tree node could contain easily more than 500 nodes, so is very important the optimization of this method. I've been trying to do this with this code, but does not work as expected:

internal static string GetNextAvailableName(TreeView treeView, string searchFor)
{
    //Check if item exists
    if (NodeExistsInSection(treeView, searchFor))
    {
        return searchFor;
    }
    else
    {
        //Initialize variables
        string nextAvailableName = searchFor;
        int counter = 0;

        Match result = Regex.Match(searchFor, @"\d $", RegexOptions.RightToLeft);
        if (result.Success)
        {
            counter = int.Parse(result.Value);
            if (searchFor.Length >= result.Value.Length)
            {
                searchFor = searchFor.Substring(0, (searchFor.Length - result.Value.Length));
            }
        }


        while (SearchRecByText(treeView, nextAvailableName) != null)
        {
            counter  ;
            nextAvailableName = string.Join("", searchFor, counter);
        }

        return nextAvailableName;
    }
}

internal static bool NodeExistsInSection(TreeView treeView, string searchFor)
{
    bool nodeExists = false;

    // Print each node recursively.  
    foreach (TreeNode n in treeView.Nodes)
    {
        //recursiveTotalNodes  ;
        if (LoopNodesRecursive(n, searchFor) != null)
        {
            nodeExists = true;
            break;
        }
    }

    return nodeExists;
}

internal static TreeNode SearchRecByText(TreeView treeView, string searchFor)
{
    TreeNode matchedNode = null;

    // Print each node recursively.  
    foreach (TreeNode n in treeView.Nodes)
    {
        //recursiveTotalNodes  ;
        matchedNode = LoopNodesRecursive(n, searchFor);
        if (matchedNode != null)
        {
            break;
        }
    }

    return matchedNode;
}

private static TreeNode LoopNodesRecursive(TreeNode treeNode, string searchFor)
{
    // Visit each node recursively.  
    foreach (TreeNode tn in treeNode.Nodes)
    {
        if (tn.Text.Equals(searchFor, StringComparison.OrdinalIgnoreCase))
        {
            return tn;
        }
    }
    return null;
}

CodePudding user response:

If performance is your outright goal I think I'd have a dictionary track treenodes with a special case for if the user enters a number. From the code posted it seems that nodes must be uniquely named across the entire tree. As such I'd build a dictionary upon tree init and maintain it as I go

Here's the method that suggests new node names based on what the user types:

Dictionary<string, int> prefixes = new();

string GetNodeName(string prefix){

    //strip trailing numbers entered by the user
    prefix = Regex.Replace(prefix, "\\d $", "");

    //have we seen the prefix before?
    var n = prefixes.GetValueOrDefault(prefix, 0);

    prefixes[prefix] = n   1;

    if(n > 0) //nth time we saw it, return number suffix 
      return prefix n;
    if(prefix == "") //user entered just a number, for the first time
      return "1";
    return prefix; //user entered a new prefix 
    
}

GetNodeName identifies the prefix text the user types by stripping off trailing numbers and checking what the next known number is for the resulting prefix. If the prefix is unknown it gets 0, 1 is then added as the next number and the 0 is special cased to "not having a numeric suffix"


If we need to restore the tree from somewhere we need to build up the max 1 values we see as we build:

 void Build(string nodename){

    //strip trailing numbers
    var prefix = Regex.Replace(prefix, "\\d $", "");

    //get the number off the end. Uses c# 8 ranges; if your c# version is less, use Remove(length) instead
    var number = int.Parse(nodename[prefix.Length..]);

    //have we seen the prefix before?
    var n = prefixes.GetValueOrDefault(prefix, 0);

    //node number is higher than dictionary? Bump dict 
    if(number >= n)
      prefixes[prefix] = number   1;
}

Call build for every node text as you rebuild your tree from DB or whatever; it will bump up the number in the prefixes dictionary to be 1 of whatever it is seeing


I assume it's a logical error to allow a user to enter a prefix of "test2" repeatedly and you will make nodes of "test2","test21",test22" - I deem that the prefix is "test", the user supplied 2 is ignored and the node gets whatever is next in line for "test" ie "test7". This logic works if the user just enters a number, the prefix is then "" and is numbered accordingly

  • Related