I have a List, with a custom class which also has a list with the same custom class, that can store a file and folder tree.
An example structure is:
Root Directory
- Directory
- Directory
- Directory
- Directory
- File
- Directory
- Directory
- Directory
- File
- Directory
- File
Because the list will represent a folder tree later, it will not be of the same structure every time.
So my question is how can I dynamically loop through such variable loop?
These are my classes where I store the tree:
public class Tree
{
public int? Id { get; set; }
public string Text { get; set; }
protected List<Tree> _children;
protected Tree _parent;
public Tree()
{
Text = string.Empty;
}
public Tree Parent { get { return _parent; } }
public Tree Root { get { return _parent == null ? this : _parent.Root; } }
public int Depth { get { return this.Ancestors().Count() - 1; } }
public IEnumerable<Tree> Children
{
get { return _children == null ? Enumerable.Empty<Tree>() : _children.ToArray(); }
}
public override string ToString()
{
return Text;
}
public void Add(Tree child)
{
if (child == null)
throw new ArgumentNullException();
if (child._parent != null)
throw new InvalidOperationException("A tree node must be removed from its parent before adding as child.");
if (this.Ancestors().Contains(child))
throw new InvalidOperationException("A tree cannot be a cyclic graph.");
if (_children == null)
{
_children = new List<Tree>();
}
Debug.Assert(!_children.Contains(child), "At this point, the node is definately not a child");
child._parent = this;
_children.Add(child);
}
public bool Remove(Tree child)
{
if (child == null)
throw new ArgumentNullException();
if (child._parent != this)
return false;
Debug.Assert(_children.Contains(child), "At this point, the node is definately a child");
child._parent = null;
_children.Remove(child);
if (!_children.Any())
_children = null;
return true;
}
}
public static class TreeBuilder
{
public static Tree BuildTree(IEnumerable<TreeNode> nodes)
{
if (nodes == null) return new Tree();
var nodeList = nodes.ToList();
var tree = FindTreeRoot(nodeList);
BuildTree(tree, nodeList);
return tree;
}
private static void BuildTree(Tree tree, IList<TreeNode> descendants)
{
var children = descendants.Where(node => node.parent == tree.Id).ToArray();
foreach (var child in children)
{
var branch = Map(child);
tree.Add(branch);
descendants.Remove(child);
}
foreach (var branch in tree.Children)
{
BuildTree(branch, descendants);
}
}
private static Tree FindTreeRoot(IList<TreeNode> nodes)
{
var rootNodes = nodes.Where(node => node.parent == null);
if (rootNodes.Count() != 1) return new Tree();
var rootNode = rootNodes.Single();
nodes.Remove(rootNode);
return Map(rootNode);
}
private static Tree Map(TreeNode node)
{
return new Tree
{
Id = node.id,
Text = node.text,
};
}
}
public class TreeNode
{
public int id { get; set; }
public string text { get; set; }
public int? parent { get; set; }
}
public static class TreeExtensions
{
public static IEnumerable<Tree> Descendants(this Tree value)
{
// a descendant is the node self and any descendant of the children
if (value == null) yield break;
yield return value;
// depth-first pre-order tree walker
foreach (var child in value.Children)
foreach (var descendantOfChild in child.Descendants())
{
yield return descendantOfChild;
}
}
public static IEnumerable<Tree> Ancestors(this Tree value)
{
// an ancestor is the node self and any ancestor of the parent
var ancestor = value;
// post-order tree walker
while (ancestor != null)
{
yield return ancestor;
ancestor = ancestor.Parent;
}
}
}
It is from this post: Codereview link
At the end I would like to map it to a list which will graphically display it. It works like the following scheme:
foreach (var children in _builtTree.Children)
{
Node child = new MyNode(children.Text);
_node.Nodes.Add(child);
}
To manually display the method I would have to add about 500 nested foreach loops which cannot be a good solution:
foreach (var children in _builtTree.Children)
{
Node child = new MyNode(children.Text);
_node.Nodes.Add(child);
foreach (var children2 in childen.Children)
{
Node child2 = new MyNode(children2.Text);
_node.Nodes.Add(child2);
foreach (var children3 in childen2.Children)
{
Node child3 = new MyNode(children3.Text);
_node.Nodes.Add(child3);
}
}
}
I hope it is understandable what I am writing. If not, feel free to leave a comment.