Creating a recursive tree

I want to create a treeview in C # that will group the file by prefix (here the prefix is โ€‹โ€‹marked with a _ separator). The following files should give this tree:

Files list:

 p_a p_a_test p_LIG p_p p_p_c p_p_c2 p_p_ccc p_p_test p_tres TestLineGraph1 TestLineGrpah 

Matching tree:

 |--p_ |--p_a |--p_a_test |--p_LIG |--p_p |--p_p_ |--p_p_c |--p_p_c2 |--p_p_ccc |--p_p_test |--p_tres TestLineGraph1 TestLineGrpah 

Here is my code attempt:

 private GraphUINode(List<string> subNodes, GraphUINode parent, string name, int lvl = 0) : base(parent.m_viewDataSubControl) { parent.Nodes.Add(this); this.Name = name; this.Text = name; string currentPrefix = ""; int pertinentSubNodes = 0; while (pertinentSubNodes < subNodes.Count -1 && subNodes[pertinentSubNodes].Split('_').Length < 2+ lvl) pertinentSubNodes++; for (int i = 0; i <= lvl; i++) { currentPrefix += subNodes[pertinentSubNodes].Split('_')[i] + "_"; } List<String> children = new List<string>(); foreach (string child in subNodes) { // The child is in the same group than the previous one if (child.StartsWith(currentPrefix)) { children.Add(child); } else { // Create a node only if needed if (children.Count > 1) { // Create the new node new GraphUINode(children, this, currentPrefix, lvl + 1); children.Clear(); children.Add(child); } else { new GraphTemplateNode(this, m_viewDataSubControl, child); } currentPrefix = ""; for (int i = 0; i <= lvl; i++) { currentPrefix += child.Split('_')[i] + "_"; } } } } 

But I missed a few in the end result:

result

How can I return it? Even when I debug step by step, I cannot find a logical way to do this.

+5
source share
1 answer

So, the first thing we want to do is take our lines and turn them into a tree. Once we have a tree, matching these nodes with a TreeView pretty simple.

We start by defining the tree itself:

 public class Node<T> { public Node(T value, IEnumerable<Node<T>> children) { Value = value; Children = children; } public T Value { get; private set; } public IEnumerable<Node<T>> Children { get; private set; } } 

Pleasant and easy, each node is simply a meaning and a collection of children.

Next, we will write a method to take a sequence of sequences and construct a tree from it. The idea here is that we will group all the elements based on the first value in their sequence, build a node for each group, and then recursively call the method in the group to get the children for this node.

 public static IList<Node<T>> GroupToTree<T>(this IEnumerable<IEnumerable<T>> source) { return GroupToTree(source.Select(sequence => sequence.GetEnumerator())); } private static IList<Node<T>> GroupToTree<T>(IEnumerable<IEnumerator<T>> source) { return source.WhereHasNext() .GroupBy(iterator => iterator.Current) .Select(group => new Node<T>(group.Key, GroupToTree(group))) .ToList(); } //This ensures that the iterators all get disposed private static IEnumerable<IEnumerator<T>> WhereHasNext<T>( this IEnumerable<IEnumerator<T>> source) { foreach (var iterator in source) { if (iterator.MoveNext()) yield return iterator; else iterator.Dispose(); } } 

Now we can take the raw data, split each of the lines into a sequence of lines, and then match each of the nodes that we have here in the nodes based on the UI for presentation:

 List<string> rawData = new List<string>(); //TODO populate raw data Func<Node<string>, TreeNode> selector = null; selector = node => new TreeNode(node.Value, node.Children.Select(selector).ToArray()); var nodes = rawData.Select(line => line.Split('_').AsEnumerable()) .GroupToTree() .Select(selector); 
+4
source

Source: https://habr.com/ru/post/1209246/


All Articles