Something like this should work:
public class Node
{
public string Key { get; set; }
public Node Parent { get; set; }
public IList<Node> Children { get; set; }
}
private Node LoadAll(string[] keys)
{
var nodes = new Dictionary<string, Node>(StringComparer.OrdinalIgnoreCase);
var orphanNodes = new List<Node>();
Node root = null;
foreach (var key in keys)
{
var node = new Node()
{
Key = key
};
nodes[key] = node;
int keySeparator = key.LastIndexOf("-");
if (keySeparator != -1)
{
string parentKey = key.Substring(0, keySeparator);
if (nodes.TryGetValue(parentKey, out var parentNode))
{
if (parentNode.Children == null)
{
parentNode.Children = new List<Node>();
}
node.Parent = parentNode;
parentNode.Children.Add(node);
}
else
{
orphanNodes.Add(node);
}
}
else if (root != null)
{
throw new Exception("Root node already exists.");
}
else
{
root = node;
}
}
foreach (var orphan in orphanNodes)
{
string parentKey = orphan.Key.Substring(0, orphan.Key.LastIndexOf("-"));
if (nodes.TryGetValue(parentKey, out var parentNode))
{
if (parentNode.Children == null)
{
parentNode.Children = new List<Node>();
}
orphan.Parent = parentNode;
parentNode.Children.Add(orphan);
}
else
{
throw new Exception("Nodes without parents found.");
}
}
return root;
}
It maintains a list of all nodes (nodes) with their keys, so that any node can easily be looked up form its key. It also maintains a list of nodes for which we didn't have any parents for on the initial loop run through (orphanNodes - you can remove this if your parent nodes always come before your child nodes).
For each key we:
- Create an instance of node
- Extract the parent key
- If there is no parent key, assume it's the root element
- Try to locate the parent node. If it's found, add the current node as a child. If it isn't found, add the current node as an orphan.
In case any parent nodes were loaded after their children, we then do the following for every orphan:
- Extract the parent key.
- Try to locate the parent node. If it's found, add the current node as a child. If it isn't found, throw an error.
Some of the string manipulation could maybe be improved, but this is a way you could approach the situation.
Dictionary<string, Node>. The dictionary key will be like `Root-Node1'. Then, simply remove the last part of the child key and use the resulting key to find its parent in the dictionary.