I was looking for a tree or graph data structure in C#, but I guess there isn't one provided. An Extensive Examination of Data Structures Using C# 2.0 a bit about why. Is there a convenient library which is commonly used to provide this functionality? Perhaps through a strategy pattern to solve the issues presented in the article.
I feel a bit silly implementing my own tree, just as I would implementing my own ArrayList.
I just want a generic tree which can be unbalanced. Think of a directory tree. C5 looks nifty, but their tree structures seem to be implemented as balanced red-black trees better suited to search than representing a hierarchy of nodes.
My best advice would be that there is no standard tree data structure because there are so many ways you could implement it that it would be impossible to cover all bases with one solution. The more specific a solution, the less likely it is applicable to any given problem. I even get annoyed with LinkedList - what if I want a circular linked list?
The basic structure you'll need to implement will be a collection of nodes, and here are some options to get you started. Let's assume that the class Node is the base class of the entire solution.
If you need to only navigate down the tree, then a Node class needs a List of children.
If you need to navigate up the tree, then the Node class needs a link to its parent node.
Build an AddChild method that takes care of all the minutia of these two points and any other business logic that must be implemented (child limits, sorting the children, etc.)
delegate void TreeVisitor<T>(T nodeData);
class NTree<T>
{
private T data;
private LinkedList<NTree<T>> children;
public NTree(T data)
{
this.data = data;
children = new LinkedList<NTree<T>>();
}
public void AddChild(T data)
{
children.AddFirst(new NTree<T>(data));
}
public NTree<T> GetChild(int i)
{
foreach (NTree<T> n in children)
if (--i == 0)
return n;
return null;
}
public void Traverse(NTree<T> node, TreeVisitor<T> visitor)
{
visitor(node.data);
foreach (NTree<T> kid in node.children)
Traverse(kid, visitor);
}
}
Simple recursive implementation...
< 40 lines of code...
You just need to keep a reference to the root of the tree outside of the class,
or wrap it in another class, maybe rename to TreeNode??
Here's mine, which is very similar to Aaron Gage's, just a little more conventional, in my opinion. For my purposes, I haven't ran into any performance issues with List<T>. It would be easy enough to switch to a LinkedList if needed.
namespace Overby.Collections
{
public class TreeNode<T>
{
private readonly T _value;
private readonly List<TreeNode<T>> _children = new List<TreeNode<T>>();
public TreeNode(T value)
{
_value = value;
}
public TreeNode<T> this[int i]
{
get { return _children[i]; }
}
public TreeNode<T> Parent { get; private set; }
public T Value { get { return _value; } }
public ReadOnlyCollection<TreeNode<T>> Children
{
get { return _children.AsReadOnly(); }
}
public TreeNode<T> AddChild(T value)
{
var node = new TreeNode<T>(value) {Parent = this};
_children.Add(node);
return node;
}
public TreeNode<T>[] AddChildren(params T[] values)
{
return values.Select(AddChild).ToArray();
}
public bool RemoveChild(TreeNode<T> node)
{
return _children.Remove(node);
}
public void Traverse(Action<T> action)
{
action(Value);
foreach (var child in _children)
child.Traverse(action);
}
public IEnumerable<T> Flatten()
{
return new[] {Value}.Concat(_children.SelectMany(x => x.Flatten()));
}
}
}
Yet another tree structure:
public class TreeNode<T> : IEnumerable<TreeNode<T>>
{
public T Data { get; set; }
public TreeNode<T> Parent { get; set; }
public ICollection<TreeNode<T>> Children { get; set; }
public TreeNode(T data)
{
this.Data = data;
this.Children = new LinkedList<TreeNode<T>>();
}
public TreeNode<T> AddChild(T child)
{
TreeNode<T> childNode = new TreeNode<T>(child) { Parent = this };
this.Children.Add(childNode);
return childNode;
}
... // for iterator details see below link
}
Sample usage:
TreeNode<string> root = new TreeNode<string>("root");
{
TreeNode<string> node0 = root.AddChild("node0");
TreeNode<string> node1 = root.AddChild("node1");
TreeNode<string> node2 = root.AddChild("node2");
{
TreeNode<string> node20 = node2.AddChild(null);
TreeNode<string> node21 = node2.AddChild("node21");
{
TreeNode<string> node210 = node21.AddChild("node210");
TreeNode<string> node211 = node21.AddChild("node211");
}
}
TreeNode<string> node3 = root.AddChild("node3");
{
TreeNode<string> node30 = node3.AddChild("node30");
}
}
BONUS
See fully-fledged tree with:
iterator
searching
Java/C#
https://github.com/gt4dev/yet-another-tree-structure
The generally excellent C5 Generic Collection Library has several different tree-based data structures, including sets, bags and dictionaries. Source code is available if you want to study their implementation details. (I have used C5 collections in production code with good results, although I haven't used any of the tree structures specifically.)
See https://github.com/YaccConstructor/QuickGraph (previously http://quickgraph.codeplex.com/)
QuickGraph provides generic directed/undirected graph data structures and algorithms for .NET 2.0 and up. QuickGraph comes with algorithms such as depth-first search, breadth-first search, A* search, shortest path, k-shortest path, maximum flow, minimum spanning tree, least common ancestors, etc... QuickGraph supports MSAGL, GLEE, and Graphviz to render the graphs, serialization to GraphML, etc.
Here's my own:
class Program
{
static void Main(string[] args)
{
var tree = new Tree<string>()
.Begin("Fastfood")
.Begin("Pizza")
.Add("Margherita")
.Add("Marinara")
.End()
.Begin("Burger")
.Add("Cheese burger")
.Add("Chili burger")
.Add("Rice burger")
.End()
.End();
tree.Nodes.ForEach(p => PrintNode(p, 0));
Console.ReadKey();
}
static void PrintNode<T>(TreeNode<T> node, int level)
{
Console.WriteLine("{0}{1}", new string(' ', level * 3), node.Value);
level++;
node.Children.ForEach(p => PrintNode(p, level));
}
}
public class Tree<T>
{
private Stack<TreeNode<T>> m_Stack = new Stack<TreeNode<T>>();
public List<TreeNode<T>> Nodes { get; } = new List<TreeNode<T>>();
public Tree<T> Begin(T val)
{
if (m_Stack.Count == 0)
{
var node = new TreeNode<T>(val, null);
Nodes.Add(node);
m_Stack.Push(node);
}
else
{
var node = m_Stack.Peek().Add(val);
m_Stack.Push(node);
}
return this;
}
public Tree<T> Add(T val)
{
m_Stack.Peek().Add(val);
return this;
}
public Tree<T> End()
{
m_Stack.Pop();
return this;
}
}
public class TreeNode<T>
{
public T Value { get; }
public TreeNode<T> Parent { get; }
public List<TreeNode<T>> Children { get; }
public TreeNode(T val, TreeNode<T> parent)
{
Value = val;
Parent = parent;
Children = new List<TreeNode<T>>();
}
public TreeNode<T> Add(T val)
{
var node = new TreeNode<T>(val, this);
Children.Add(node);
return node;
}
}
Output:
Fastfood
Pizza
Margherita
Marinara
Burger
Cheese burger
Chili burger
Rice burger
I have a little extension to the solutions.
Using a recursive generic declaration and a deriving subclass, you can better concentrate on your actual target.
Notice, it’s different from a non generic implementation, you don’t need to cast 'node' to 'NodeWorker'.
Here's my example:
public class GenericTree<T> where T : GenericTree<T> // recursive constraint
{
// no specific data declaration
protected List<T> children;
public GenericTree()
{
this.children = new List<T>();
}
public virtual void AddChild(T newChild)
{
this.children.Add(newChild);
}
public void Traverse(Action<int, T> visitor)
{
this.traverse(0, visitor);
}
protected virtual void traverse(int depth, Action<int, T> visitor)
{
visitor(depth, (T)this);
foreach (T child in this.children)
child.traverse(depth + 1, visitor);
}
}
public class GenericTreeNext : GenericTree<GenericTreeNext> // concrete derivation
{
public string Name {get; set;} // user-data example
public GenericTreeNext(string name)
{
this.Name = name;
}
}
static void Main(string[] args)
{
GenericTreeNext tree = new GenericTreeNext("Main-Harry");
tree.AddChild(new GenericTreeNext("Main-Sub-Willy"));
GenericTreeNext inter = new GenericTreeNext("Main-Inter-Willy");
inter.AddChild(new GenericTreeNext("Inter-Sub-Tom"));
inter.AddChild(new GenericTreeNext("Inter-Sub-Magda"));
tree.AddChild(inter);
tree.AddChild(new GenericTreeNext("Main-Sub-Chantal"));
tree.Traverse(NodeWorker);
}
static void NodeWorker(int depth, GenericTreeNext node)
{ // a little one-line string-concatenation (n-times)
Console.WriteLine("{0}{1}: {2}", String.Join(" ", new string[depth + 1]), depth, node.Name);
}
Try this simple sample.
public class TreeNode<TValue>
{
#region Properties
public TValue Value { get; set; }
public List<TreeNode<TValue>> Children { get; private set; }
public bool HasChild { get { return Children.Any(); } }
#endregion
#region Constructor
public TreeNode()
{
this.Children = new List<TreeNode<TValue>>();
}
public TreeNode(TValue value)
: this()
{
this.Value = value;
}
#endregion
#region Methods
public void AddChild(TreeNode<TValue> treeNode)
{
Children.Add(treeNode);
}
public void AddChild(TValue value)
{
var treeNode = new TreeNode<TValue>(value);
AddChild(treeNode);
}
#endregion
}
I created a Node<T> class that could be helpful for other people. The class has properties like:
Children
Ancestors
Descendants
Siblings
Level of the node
Parent
Root
Etc.
There is also the possibility to convert a flat list of items with an Id and a ParentId to a tree. The nodes holds a reference to both the children and the parent, so that makes iterating nodes quite fast.
There is the now released .NET codebase: specifically the code for a SortedSet that implements a red-black tree: sortedset.cs
This is, however, a balanced tree structure. So my answer is more a reference to what I believe is the only native tree-structure in the .NET core library.
I've completed the code that Berezh has shared.
public class TreeNode<T> : IEnumerable<TreeNode<T>>
{
public T Data { get; set; }
public TreeNode<T> Parent { get; set; }
public ICollection<TreeNode<T>> Children { get; set; }
public TreeNode(T data)
{
this.Data = data;
this.Children = new LinkedList<TreeNode<T>>();
}
public TreeNode<T> AddChild(T child)
{
TreeNode<T> childNode = new TreeNode<T>(child) { Parent = this };
this.Children.Add(childNode);
return childNode;
}
public IEnumerator<TreeNode<T>> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
}
public class TreeNodeEnum<T> : IEnumerator<TreeNode<T>>
{
int position = -1;
public List<TreeNode<T>> Nodes { get; set; }
public TreeNode<T> Current
{
get
{
try
{
return Nodes[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public TreeNodeEnum(List<TreeNode<T>> nodes)
{
Nodes = nodes;
}
public void Dispose()
{
}
public bool MoveNext()
{
position++;
return (position < Nodes.Count);
}
public void Reset()
{
position = -1;
}
}
I have added a complete solution and example using the NTree class above. I also added the "AddChild" method...
public class NTree<T>
{
public T data;
public LinkedList<NTree<T>> children;
public NTree(T data)
{
this.data = data;
children = new LinkedList<NTree<T>>();
}
public void AddChild(T data)
{
var node = new NTree<T>(data) { Parent = this };
children.AddFirst(node);
}
public NTree<T> Parent { get; private set; }
public NTree<T> GetChild(int i)
{
foreach (NTree<T> n in children)
if (--i == 0)
return n;
return null;
}
public void Traverse(NTree<T> node, TreeVisitor<T> visitor, string t, ref NTree<T> r)
{
visitor(node.data, node, t, ref r);
foreach (NTree<T> kid in node.children)
Traverse(kid, visitor, t, ref r);
}
}
public static void DelegateMethod(KeyValuePair<string, string> data, NTree<KeyValuePair<string, string>> node, string t, ref NTree<KeyValuePair<string, string>> r)
{
string a = string.Empty;
if (node.data.Key == t)
{
r = node;
return;
}
}
Using it
NTree<KeyValuePair<string, string>> ret = null;
tree.Traverse(tree, DelegateMethod, node["categoryId"].InnerText, ref ret);
There is also the possibility to use XML with LINQ:
Create XML tree in C# (LINQ to XML)
XML is the most mature and flexible solution when it comes to using trees and LINQ provides you with all the tools that you need.
The configuration of your tree also gets much cleaner and user-friendly as you can simply use an XML file for the initialization.
If you need to work with objects, you can use XML serialization:
XML serialization
Most trees are formed by the data you are processing.
Say you have a person class that includes details of someone’s
parents, would you rather have the tree structure as part of your
“domain class”, or use a separate tree class that contained links to
your person objects? Think about a simple operation like getting all
the grandchildren of a person, should this code be in the person
class, or should the user of the person class have to know about a
separate tree class?
Another example is a parse tree in a compiler…
Both of these examples show that the concept of a tree is part of the domain of the data and using a separate general-purpose tree at least doubles the number of objects that are created as well as making the API harder to program again.
We want a way to reuse the standard tree operations, without having to reimplement them for all trees, while at the same time, not having to use a standard tree class. Boost has tried to solve this type of problem for C++, but I am yet to see any effect for .NET to get it adapted.
If you are going to display this tree on the GUI, you can use TreeView and TreeNode. (I suppose technically you can create a TreeNode without putting it on a GUI, but it does have more overhead than a simple homegrown TreeNode implementation.)
Here is my implementation of a BST:
class BST
{
public class Node
{
public Node Left { get; set; }
public object Data { get; set; }
public Node Right { get; set; }
public Node()
{
Data = null;
}
public Node(int Data)
{
this.Data = (object)Data;
}
public void Insert(int Data)
{
if (this.Data == null)
{
this.Data = (object)Data;
return;
}
if (Data > (int)this.Data)
{
if (this.Right == null)
{
this.Right = new Node(Data);
}
else
{
this.Right.Insert(Data);
}
}
if (Data <= (int)this.Data)
{
if (this.Left == null)
{
this.Left = new Node(Data);
}
else
{
this.Left.Insert(Data);
}
}
}
public void TraverseInOrder()
{
if(this.Left != null)
this.Left.TraverseInOrder();
Console.Write("{0} ", this.Data);
if (this.Right != null)
this.Right.TraverseInOrder();
}
}
public Node Root { get; set; }
public BST()
{
Root = new Node();
}
}
Tree With Generic Data
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
public class Tree<T>
{
public T Data { get; set; }
public LinkedList<Tree<T>> Children { get; set; } = new LinkedList<Tree<T>>();
public Task Traverse(Func<T, Task> actionOnNode, int maxDegreeOfParallelism = 1) => Traverse(actionOnNode, new SemaphoreSlim(maxDegreeOfParallelism, maxDegreeOfParallelism));
private async Task Traverse(Func<T, Task> actionOnNode, SemaphoreSlim semaphore)
{
await actionOnNode(Data);
SafeRelease(semaphore);
IEnumerable<Task> tasks = Children.Select(async input =>
{
await semaphore.WaitAsync().ConfigureAwait(false);
try
{
await input.Traverse(actionOnNode, semaphore).ConfigureAwait(false);
}
finally
{
SafeRelease(semaphore);
}
});
await Task.WhenAll(tasks);
}
private void SafeRelease(SemaphoreSlim semaphore)
{
try
{
semaphore.Release();
}
catch (Exception ex)
{
if (ex.Message.ToLower() != "Adding the specified count to the semaphore would cause it to exceed its maximum count.".ToLower())
{
throw;
}
}
}
public async Task<IEnumerable<T>> ToList()
{
ConcurrentBag<T> lst = new ConcurrentBag<T>();
await Traverse(async (data) => lst.Add(data));
return lst;
}
public async Task<int> Count() => (await ToList()).Count();
}
Unit Tests
using System.Threading.Tasks;
using Xunit;
public class Tree_Tests
{
[Fact]
public async Task Tree_ToList_Count()
{
Tree<int> head = new Tree<int>();
Assert.NotEmpty(await head.ToList());
Assert.True(await head.Count() == 1);
// child
var child = new Tree<int>();
head.Children.AddFirst(child);
Assert.True(await head.Count() == 2);
Assert.NotEmpty(await head.ToList());
// grandson
child.Children.AddFirst(new Tree<int>());
child.Children.AddFirst(new Tree<int>());
Assert.True(await head.Count() == 4);
Assert.NotEmpty(await head.ToList());
}
[Fact]
public async Task Tree_Traverse()
{
Tree<int> head = new Tree<int>() { Data = 1 };
// child
var child = new Tree<int>() { Data = 2 };
head.Children.AddFirst(child);
// grandson
child.Children.AddFirst(new Tree<int>() { Data = 3 });
child.Children.AddLast(new Tree<int>() { Data = 4 });
int counter = 0;
await head.Traverse(async (data) => counter += data);
Assert.True(counter == 10);
counter = 0;
await child.Traverse(async (data) => counter += data);
Assert.True(counter == 9);
counter = 0;
await child.Children.First!.Value.Traverse(async (data) => counter += data);
Assert.True(counter == 3);
counter = 0;
await child.Children.Last!.Value.Traverse(async (data) => counter += data);
Assert.True(counter == 4);
}
}
I don't like a tree aproach. It gets things overcomplicated including search or dril-down or even ui controls populating.
I would suggest to use a very simple approach with IDictionary<TChild, TParent>. This also allows to have no connections between nodes or levels.
In case you need a rooted tree data structure implementation that uses less memory, you can write your Node class as follows (C++ implementation):
class Node {
Node* parent;
int item; // depending on your needs
Node* firstChild; //pointer to left most child of node
Node* nextSibling; //pointer to the sibling to the right
}
Related
I do understand how both interfaces (IEnumerator and IEnumerable) work and what they are used for. However, I never quite understood when to create a class that is derived from one of these two interfaces. You can do a foreach loop on a list, on an array, and other generic collections as far as I am aware without having to create a class like I did in my code:
class Program
{
public static int[] array = new int[3] { 1, 2, 3 };
static void Main(string[] args)
{
var Enumerable = new Aninfiniteenumerator();
foreach(var i in infiniteEnumerable)
{
Console.WriteLine($"I is {i}");
}
Console.ReadKey();
}
}
class Aninfiniteenumerator : IEnumerable<int> //Creating a class that is derived from IEnumerable
{
public IEnumerator GetEnumerator()
{
return new MyInfiniteEnumer(Program.array);
}
IEnumerator<int> IEnumerable<int>.GetEnumerator()
{
return new MyInfiniteEnumer(Program.array);
}
}
public class MyInfiniteEnumer : IEnumerator<int> ////Creating a class that is derived from IEnumerator
{
private int[] values;
private int index = -1;
public int Current => values[index];
object IEnumerator.Current => Current;
public MyInfiniteEnumer (int [] values)
{
this.values = values;
}
public void Dispose()
{
}
public bool MoveNext()
{
index++;
return index < values.Length;
}
public void Reset()
{
}
}
PS. I know that my enumerators are called "infinite enumerators" yet they are not infinite. So, as I have said, it is possible to do a foreach loop over a generic list/an array without having to create an IEnumerable/IEnumerator classes:
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
List<Car> vehicles = new List<Car>();
for(int i = 0; i < 100; i++)
{
vehicles.Add(new Car(rand.Next(1970,2021), "Honda"));
}
foreach(var car in vehicles)
{
Console.WriteLine(car.yearProduced + ", " + car.model);
}
Console.ReadKey();
for (int i = 0; i < 100; i++)
{
vehicles.Add(new Car(rand.Next(1970, 2021), "Subaru"));
}
foreach (var car in vehicles)
{
Console.WriteLine(car.yearProduced + ", " + car.model);
}
Console.WriteLine(vehicles.Count());
Console.ReadKey();
}
}
class Car
{
public string model { get; set; }
public int yearProduced { get; set; }
public Car (int year, string model)
{
yearProduced = year;
this.model = model;
}
}
Back to my question, I wrote the first code to be able to do a foreach loop over the var called "Enumerable". I only wrote this code for practice and see no practical use of creating classes that are derived from IEnumerable and IEnumerator. So, my question is, what are some situations where you'd have to create a class that is derived from one of these two interfaces?
A good example of a custom structure that could use the enumerator is the binary tree.
A simplest tree would be
public class Tree
{
public Tree Left { get; set; }
public Tree Right { get; set; }
public object Value { get; set; }
}
This definition can be used to compose arbitrary trees:
var root = new Tree()
{
Left = new Tree() { Value = 1 },
Right = new Tree() { Value = 2 },
Value = 3
}
Note that my tree is balanced but actual trees don't have to be.
Now, how are you supposed to enumerate all values? It's not that easy, in each node you have to decide whether or not it has subnodes and when you are done at the node, you have to go back to its parent and explore all paths.
But the client code is not interested in whether or not it's difficult, it expects the code to be
foreach ( var val in root )
{
// I want all values from the tree here!
}
This is when the idea of enumeration starts to make sense. It's not only about simple, linear structures, like arrays or lists!
public class Tree : IEnumerable
{
public IEnumerator GetEnumerator()
{
if ( Left != null ) foreach ( var e in Left ) yield return e;
if ( Right != null ) foreach ( var e in Right ) yield return e;
yield return Value;
}
}
I hope this example sheds some lights on the issue.
I've just started learning how to program and have been following along with this tutorial on graphs but I've run into some issues using the given
AddDirectedEdge(GraphNode<T> from, GraphNode<T> to, int cost)
It fails to build using the default from the tutorial, for example
web.AddDirectedEdge("People.aspx", "Privacy.htm"); // People -> Privacy
This gives the error "No overload for method 'AddDirectedEdge' takes 2 arguments". Adding an integer as a third argument does not help either, it just gives another error "Argument#: cannot convert from 'string' to 'GraphTest.GraphNode< string>'"
I'm not sure how to fix this, any help/insight regarding it would be appreciated. For ease of viewing the graph and graph node classes are shown below (these are all available through the above link as well):
public class GraphNode<T> : Node<T>
{
private List<int> costs;
public GraphNode() : base() { }
public GraphNode(T value) : base(value) { }
public GraphNode(T value, NodeList<T> neighbors) : base(value, neighbors) { }
new public NodeList<T> Neighbors
{
get
{
if (base.Neighbors == null)
base.Neighbors = new NodeList<T>();
return base.Neighbors;
}
}
public List<int> Costs
{
get
{
if (costs == null)
costs = new List<int>();
return costs;
}
}
}
.
public class Graph<T> : IEnumerable<T>
{
private NodeList<T> nodeSet;
public Graph() : this(null) { }
public Graph(NodeList<T> nodeSet)
{
if (nodeSet == null)
this.nodeSet = new NodeList<T>();
else
this.nodeSet = nodeSet;
}
public void AddNode(GraphNode<T> node)
{
// adds a node to the graph
nodeSet.Add(node);
}
public void AddNode(T value)
{
// adds a node to the graph
nodeSet.Add(new GraphNode<T>(value));
}
public void AddDirectedEdge(GraphNode<T> from, GraphNode<T> to, int cost)
{
from.Neighbors.Add(to);
from.Costs.Add(cost);
}
public void AddUndirectedEdge(GraphNode<T> from, GraphNode<T> to, int cost)
{
from.Neighbors.Add(to);
from.Costs.Add(cost);
to.Neighbors.Add(from);
to.Costs.Add(cost);
}
public bool Contains(T value)
{
return nodeSet.FindByValue(value) != null;
}
public bool Remove(T value)
{
// first remove the node from the nodeset
GraphNode<T> nodeToRemove = (GraphNode<T>)nodeSet.FindByValue(value);
if (nodeToRemove == null)
// node wasn't found
return false;
// otherwise, the node was found
nodeSet.Remove(nodeToRemove);
// enumerate through each node in the nodeSet, removing edges to this node
foreach (GraphNode<T> gnode in nodeSet)
{
int index = gnode.Neighbors.IndexOf(nodeToRemove);
if (index != -1)
{
// remove the reference to the node and associated cost
gnode.Neighbors.RemoveAt(index);
gnode.Costs.RemoveAt(index);
}
}
return true;
}
public NodeList<T> Nodes
{
get
{
return nodeSet;
}
}
public int Count
{
get { return nodeSet.Count; }
}
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
throw new NotImplementedException();
}
}
Well, obviously it is complaining about type mismatch:
you are supplying string type instead of GraphNode<T>.
Instead you should call it as:
web.AddDirectedEdge(new GraphNode("People.aspx"), new GraphNode("Privacy.htm"), 1);
where 1 is a cost, which is required, or
var ppl = new GraphNode("People.aspx");
var prv = new GraphNode("Privacy.htm");
web.AddDirectedEdge(ppl, prv, 1);
if you like to reuse nodes further in code.
As a side note, it seems you are making some trivial mistakes. Before making it further I strongly recommend you to take at least basic course of C#. There is plenty of then available for free in the Web, this for example.
I have a generic tree node class ObservableTreeNode<K,V>, with a method that should go through all nodes of a tree and examine them. I have two more classes:
ElementTreeNode : ObservableTreeNode<string, HierarchyElement>, and
ElementTreeNodeVisual : ElementTreeNode.
The generic class looks like this:
public class ObservableTreeNode<K, V>
{
public K Key { get; set; }
public V Value { get; set; }
public ObservableCollection<ObservableTreeNode<K, V>> Children { get; set; }
public ObservableTreeNode()
{
this.Children = new ObservableCollection<ObservableTreeNode<K, V>>();
}
public static IEnumerable<T> FindNodeInTree<T>(
T rootNode, Func<T, bool> predicate, bool firstOnly = false
) where T : ObservableTreeNode<K, V>
{
var resultNodes = new List<T>();
var nodeQueue = new Queue<T>();
nodeQueue.Enqueue(rootNode);
while (nodeQueue.Any())
{
T currentNode = nodeQueue.Dequeue();
Debug.WriteLine("Current node key: {0}", currentNode.Key);
if (predicate(currentNode))
{
Debug.WriteLine("Match!");
resultNodes.Add(currentNode);
if (firstOnly)
{
Debug.WriteLine("-FindInContext");
return resultNodes;
}
}
Debug.WriteLine("The current node has {0} children.", currentNode.Children.Count);
foreach (T n in currentNode.Children)
{
Debug.WriteLine("Enqueue child...");
nodeQueue.Enqueue(n);
}
}
return resultNodes;
}
}
In my ElementTreeNodeVisual class, I must hide the Children property with a new one, otherwise the 3rd party (Infragistics' XamDataTree) control in my WPF application wouldn't enumerate the child nodes. So my ElementTreeNodeVisual class looks like this:
public class ElementTreeNodeVisual : ElementTreeNode
{
public bool IsExpanded { get; set; }
public bool IsSelected { get; set; }
public new ObservableCollection<ElementTreeNodeVisual> Children
{
get;
set;
}
public ElementTreeNodeVisual(ElementTreeNode elementTreeNode)
{
this.Children = new ObservableCollection<ElementTreeNodeVisual>();
this.Element = elementTreeNode.Element;
this.Parent = elementTreeNode.Parent;
foreach (ElementTreeNode child in elementTreeNode.Children)
{
this.Children.Add(new ElementTreeNodeVisual(child));
}
}
}
}
My problem is, when I try call the ElementTreeNodeVisual.FindNodeInTree method, the method seems to be seeing the Children property of the base class - which has no items.
This is how I call the method:
Func<ElementTreeNodeVisual, bool> isExpandedFunc = delegate(ElementTreeNodeVisual node) { return node.IsExpanded; };
foreach (ElementTreeNodeVisual node in _hierarchyNodeVisuals)
{
var expandedNodes = ElementTreeNodeVisual.FindNodeInTree<ElementTreeNodeVisual>(node, isExpandedFunc);
foreach (ElementTreeNode expandedNode in expandedNodes)
{
expandedNodeIds.Add(expandedNode.Key);
}
}
If I set a watch on the node variable inside the foreach loop, it shows the new Children property, with several child nodes. The Debug.WriteLine(...) in the FindNodeInTree method however, says there are 0 children.
As an emergency solution, I've copy-pasted the FindNodeInTree method and changed the T parameter to where T : ElementTreeNodeVisual. It works like this, but in the end there shouldn't be any copy-pasted code in there...
What should I change (either in the generic class or the child class) to make the FindNodeInTree method see the new property, when it's called on the child class?
Well, It's a little strange method but it should work.
First, add a virtual property collection in your base class. For example:
public virtual ObservableCollection<ObservableTreeNode<K, V>> VirtualChildren {
get { return Children; }
}
In your searching method change Children to VirtualChildren:
public static IEnumerable<T> FindNodeInTree<T>(
T rootNode, Func<T, bool> predicate, bool firstOnly = false
) where T : ObservableTreeNode<K, V>
{
var resultNodes = new List<T>();
var nodeQueue = new Queue<T>();
nodeQueue.Enqueue(rootNode);
while (nodeQueue.Any())
{
T currentNode = nodeQueue.Dequeue();
Debug.WriteLine("Current node key: {0}", currentNode.Key);
if (predicate(currentNode))
{
Debug.WriteLine("Match!");
resultNodes.Add(currentNode);
if (firstOnly)
{
Debug.WriteLine("-FindInContext");
return resultNodes;
}
}
Debug.WriteLine("The current node has {0} children.", currentNode.VirtualChildren.Count);
foreach (T n in currentNode.VirtualChildren)
{
Debug.WriteLine("Enqueue child...");
nodeQueue.Enqueue(n);
}
}
return resultNodes;
}
And override VirtualChildren property in ElementTreeNodeVisual:
public override ObservableCollection<ObservableTreeNode<string, HierarchyElement>> VirtualChildren
{
get { return new ObservableCollection<ObservableTreeNode<string, HierarchyElement>>(Children); }
}
Of course, returning new collection in property each time isn't very good. So you may replace this property by the virtual method or subscribe on CollectionChanged event Children property in ElementTreeNodeVisual class and add new elements to your inner collection in a real time, for instance.
I have an IList<Category>
The Category type is coming from my Category Table in SQL Server:
Table: Category
CategoryID, ParentCategoryID
so typical heirarchy in one table.
So if I have this IList of Categories that contain the node relationships, then I am trying to figure out how this fits into making a Node and Tree like a lot of people are doing. And how would the constructor look and this class be created in terms of usage?
I think it makes sense here to create a generic Node class and Tree class so I can reuse in the future I think for other tree types.
So if I have something like this, how is T being used and what am I benefiting from?
(pseudo code here)
public class Node<T>
...
Node<T> _parentNode;
List<Node<T>> _children;
private void SetParentNode(T)
private void AddChild(T)
... etc.
trying to understand the concept here on why a Generic Node class would be used for any type coming in like Childeren, etc. that contains a child/parent relationship (int Ids)
UPDATE
So having an issue here with the GroupBy recommendation. Check out what I tried to do with your example:
First I have this property in my Tree class:
public Dictionary, IList>> ParentNodeAndRelatedChildrenFlattenedMap { get; private set; }
and incoming to my class's constructor is a IList dependencies that I converted (looped and created a new Node for every one of them) to a IList>
Now I'm trying to group that list by Node.ParentId as you were talking so that I get a grouping on Parent Nodes and since each node has its children property it's easy to find out what the related children are to those parent nodes.
But here is the problem now later down in my code:
public void CreateFlattenedMap()
{
var parentGroups = _nodeDependencies.GroupBy(d => d.ParentNodeId);
var dictionary = parentGroups.ToDictionary(d => d, d => d.ToList());
ParentNodeAndRelatedChildrenFlattenedMap = dictionary;
}
well it's not liking my assignment of dictionary because it's an > dictionary that's created by the ToDictionary(). So not sure how to get this grouping grouped and to a dictionary that is a , List> where Node in the dictionary is the Node instance for that parent I'm grouping on (yea I'm grouping on its Node.ParentId but I want the Node though in the ToDictionary in the end) and the List> is the list of Children Nodes from the Parent Node.Children property.
This is what a more complete implementation would look like:
public class TreeNode<T>
{
private T _item;
private TreeNode<T> _parentNode;
private List<TreeNode<T>> _children;
public TreeNode(T item)
{
_item = item;
}
public void SetParentNode(T parent)
{
_parentNode.Item = parent;
}
public T Item
{
get { return _item; }
set { _item = value; }
}
public void AddChild(T child)
{
_children.Add(new TreeNode<T>(child));
}
public void RemoveChild(T child)
{
var node = _children.FirstOrDefault(e => e.Item.Equals(child));
if (node != null)
_children.Remove(node);
}
}
And your questions:
How would the constructor look and this class be created in terms of usage?
As you can see from the above in AddChild(), simply specify the type of the child for the constructor.
var node = new TreeNode<T>(item);
So if I have something like this, how is T being used and what am I benefiting from?
The use of generics can same a lot of time rewriting code when done right. In the implementation above, we can make a tree structure out of basically any type we want by simply changing T. So this saves us a lot of time if we need a tree structure for more than one type.
var intTreeNode = new TreeNode<int>(10);
var stringTreeNode = new TreeNode<string>("hello world");
Generically really take some exposure time before it clicks and you "just get it", keep at it.
Constructing the tree
To construct the tree from a list of categories that may or may not have parent categories you will need to iterate through the list in some way. A decent way to go about this would be to first organise them into groupings based on the ParentCategoryID and constructing the tree. Something like this (untested):
public List<TreeNode<Category>> ConstructCategories(List<Category> categories)
{
var groups = categories.GroupBy(e => e.ParentCategoryID);
var rootGroup = groups.Single(e => e.Key == null);
var categories = List<TreeNode<Category>>();
foreach (var category in rootGroup)
{
// Create and fill category
var node = new TreeNode<Category>(category);
ConstructChildrenCategories(node, groups);
categories.Add(node);
}
}
public void ConstructChildrenCategories(TreeNode<Category> node, IEnumerable<IGrouping<Category>> groups)
{
var group = groups.Single(e => e.Key == node.Item.CategoryID);
foreach (var category in group)
{
// Create and fill category
var childNode = new TreeNode<Category>(category);
ConstructChildrenCategories(childNode, groups);
// We could do this automatically in both methods.
childNode.SetParent(node.Item);
node.AddChild(childNode);
}
}
This may be helpful:
public interface ICategory
{
int Id { get; }
int ParentId { get; }
}
public class Category : ICategory
{
int id;
int parentId;
public int Id { get { return id; }}
public int ParentId { get { return parentId; }}
}
And this is the Node class:
public class Node<T> where T : ICategory
{
Node<T> _parentNode;
List<Node<T>> _children;
public Node<T> Parent { get { return _parentNode; }}
public Node<T> Child(int index) { return _children[index]; }
public T Value;
public Node(T value)
{
this.Value = value;
}
public void AddChild(T item)
{
Node<T> child = new Node<T>(item);
this._children.Add(child);
child._parentNode = this;
}
}
And this is the Tree class:
public class Tree<T> where T : ICategory
{
List<Node<T>> values;
public Tree()
{
this.values = new List<Node<T>>();
}
public Node<T> FindNode(int id)
{
if (values.Exists(input => input.Value.Id == id))
{
return values.Find(input => input.Value.Id == id);
}
else { return null; }
}
public void AddNode(T value)
{
Node<T> parent = FindNode(value.ParentId);
if (parent != null)
{
parent.AddChild(value);
}
}
}
You can't make all the function of tree and treenode.
rather add the class data to Treenode.
for example
class MyClass
{
public int A;
public string B;
}
...
TreeNode Node = TreeView.Nodes.Add("AAA");
MyClass Data = new MyClass();
Node.Tag = Data;
The Data assigned to TreeNode will not be deleted. and you can use whole tree property and Nodes member, too.
the only thing that you should do is typecast when use data of the node.
TreeNode Node = TreeView.Nodes[0];
MyClass Temp = Node.Tag as MyClass;
been struggling with this for a couple of days now and still stumped.
i have a data structure that starts with containers that can hold other containers, and eventually leaf nodes. i'm looking for a way of being to iterate thru elements of a type directly, without pulling them into another collection so i can operate on them in place and then save the resulting structure out.
The code below is a noddy version, and if you set a break point on each findElements function you'll see that it drops out without recursing. this is on mono and ms runtimes, so i'm sure it's me not getting something rather than a bug ;)
also, the function should ideally be
IEnumerable<object> findElements<T>();
but i can't get the cast to work on this line then :
if (this is T) yield return this;
should ideally be
if (this is T) yield return (T)this;
thanks for any suggestions / clarity / light
using System;
using System.Collections.Generic;
using System.Text;
namespace covariantTest {
class MainClass {
public static void Main(string[] args) {
Console.WriteLine("Starting");
Document root = new Document("rooty");
root.Children.Add(new File("file 1"));
root.Children.Add(new File("file 2"));
Document doc2 = new Document("doc2");
File file3 = new File("file 3");
file3.Lines.Add(new Line("line 1 file 3"));
file3.Lines.Add(new Line("line 2 file 3"));
doc2.Children.Add(file3);
File file4 = new File("file 4");
file4.Lines.Add(new Line("stuff about stuff"));
file4.Lines.Add(new Line("Babylon n ting"));
file4.Lines.Add(new Line("last line"));
doc2.Children.Add(file4);
root.Children.Add(doc2);
// find the lines
foreach (object obj in root.findElements<Line>()) {
Line line = obj as Line;
Console.WriteLine(line.Contents);
}
// done
Console.WriteLine("Press enter to finish");
Console.ReadLine();
}
}// Main
#region classes
public class Line : ISearchable {
private string _contents = string.Empty;
public Line() {}
public Line(string contents) {
_contents = contents;
}
#region properties
public string Contents {
get { return _contents; }
set { _contents = value; }
}
#endregion properties
public IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
}
}// Line
public class File : Container {
private List<Line> _lines = new List<Line>();
public File() : base() {}
public File(string name) : base(name) {}
#region properties
public List<Line> Lines {
get { return _lines; }
set { _lines = value; }
}
#endregion properties
public override IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
else base.findElements<T>();
}
}// File
public class Document : Container {
public Document() : base() {}
public Document(string name) : base(name) {}
public override IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
else base.findElements<T>();
}
}// Document
public abstract class Container : ISearchable {
private string _name = string.Empty;
private List<Container> _children = new List<Container>();
public Container() {}
public Container(string name) {
_name = name;
}
#region properties
public string Name {
get { return _name; }
set { _name = value; }
}
public List<Container> Children {
get { return _children; }
set { _children = value; }
}
#endregion properties
#region interfaces
public virtual IEnumerable<object> findElements<T>() {
if (this is T) yield return this;
foreach (Container item in _children) {
item.findElements<T>();
}
}
#endregion interfaces
}// Container
#endregion classes
#region interfaces
public interface ISearchable {
IEnumerable<object> findElements<T>();
}
#endregion interfaces
}// namespace
I think you code is a bit complex, but I may have bad understood you target.
Anyway, here is a sample to scan in a "flat-fashion" your tree. I also used a very small code just to show-how, but obviously you have to work on.
namespace ConsoleApplication3
{
//this is a node of your tree, but you may add whatever you want inside
class Item
{
public List<Item> Items { get; set; }
}
class Program
{
static void Main(string[] args)
{
//define the tree structure
var tree = new Item();
// (complete your tree-structrure)
//define the action delegate
Action<Item> action = (item) => Console.WriteLine(item);
//scan the hierarchy
Scan(
tree,
typeof(Item),
action);
}
//here is the flat-scan function, the "typeToFind" here is just
//for example and have very little sense to be in
static void Scan(
Item startItem,
Type typeToFind,
Action<Item> action)
{
var temp = new List<Item>();
temp.Add(startItem);
while (temp.Count > 0)
{
var item = temp[0];
temp.RemoveAt(0);
if (typeToFind.IsInstanceOfType(item))
{
action(item);
}
temp.AddRange(item.Items);
}
}
}
}
Hope this helps. Cheers.
How do you expect it to work? If I understand it correctly, then yield does not work when called from another function (so if you call base.findElements then you ain't gonna get any results from it). I suggest rewriting it without yield. To avoid creating many lists, I would pass list as a parameter, in such a way:
public interface ISearchable {
void doFindElements<T>(List<T> putThemHere);
}
// this is extender for syntactical sugar
public static class SearchableExtender
{
public static IEnumerable<T> findElements<T>(this ISearchable obj)
{
List<T> result = new List<T>();
obj.doFindElements(result);
return result;
}
}
public abstract class Container : ISearchable {
...
public virtual void doFindElements<T>(List<T> putThemHere)
{
if (this is T) putThemHere.Add(this);
foreach (Container item in _children) { item.doFindElements(putThemHere); }
}
...
}
By the way, you don't need to override doFindElements in Document, inherited version from Container will do OK, as "this" would mean a Document here. Implementation of File is completely wrong. Base Container class would not see Lines property and instead would use empty Children property. There are two ways to work around this:
You need to kill _lines and instead work with _children from the base class (for example, you can make Collection<Line> descendent that would be a wrapper around _children class by overriding InsertItem, SetItem, RemoveItem and ClearItems and calling appropriate methods of _children).
Remove _children from Container, instead make virtual abstract function IEnumerable GetChildElements() that each descendent would implement and return its own List<> of child elements. In doFindElements you would call that function instead of _children. You can even make second base class, like UntypedContainer: Container that would declare List<Container> _children, override GetChildElements() to return _children and inherit Document from it. File would still be inherited from simple Container, as it have its own children list.
The second way is simpler and better.