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:
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:
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