I was wondering if it is possible to pass a 'parent container' to an object initialization using single statement initialization? I am thinking about using this approach for hierarchical unit test variable assignments; thank you in advanced.
public class ParentObj
{
public IList<ChildObj> Children { get; set; }
}
public class ChildObj
{
private ParentObj Parent { get; set; }
public ChildObj(ParentObj parentObj) => Parent = parentObj;
}
class Program
{
static void Main(string[] args)
{
var parents = new List<ParentObj>();
var parent = new ParentObj();
parent.Children.Add(new ChildObj(parent));
parents.Add(parent);
// Anyway to duplicate the above with this style of initialization?
var moreParents = new List<ParentObj>
{
new ParentObj
{
Children = new List<ChildObj>
{
//new ChildObj( [need a reference to the parentObj] );
}
}
};
}
}
No, because at the time the Children are constructed your code doesn't have a reference to the parent. It's like C# is holding all the references for you, and doing all the linking, and just giving you the one end result (moreParents) object and you place it into the only thing you have a named reference for
You could change things like this:
public class ParentObj
{
private IList<ChildObj> _children;
public IList<ChildObj> Children {
get { return _children; }
set {
_children = value;
foreach (ChildObj c in value)
c.Parent = this;
}
}
}
public class ChildObj
{
public ParentObj Parent { get; set; }
}
So that the parent of the child can be set later, and then this code will work out:
var moreParents = new List<ParentObj>
{
new ParentObj
{
Children = new List<ChildObj>
{
new ChildObj(), new ChildObj()
}
}
};
Because you do have a way of referring to the parent (this)
Really, if you want to have some simple way of creating parents and children you need to create something that constructs them, so it can make a parent, and then then children supplying that parent.. Kinda like what you had in your first example!
ps; I'm not a fan of the "parent" and "child" terms of reference for this structure; they're normally used for inheritance hierarchies, where Child is-a Parent, rather than for container hierarchies where Parent has-a Children
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.
This is a Two (2) Part Question about Generics
I've got to create several similar classes to model similarly designed database tables.
All tables contain an ID int and a Text nvarchar(50) field. One or two may contain a few other fields.
I rarely use generics, but I see examples of it on here quite frequently. This is my largest attempt to create a generic class that is used in another generic class.
My basic construct is as follows, and I will point out with a comment what does not work and the error message Visual Studio 2010 is displaying:
public class IdText {
public IdText(int id, string text) {
ID = id;
Text = text;
}
public int ID { get; private set; }
public string Text { get; private set; }
}
public class TCollection<T> : IEnumerable<T> where T : IdText {
private List<T> list;
public TCollection() {
list = new List<T>();
}
public void Add(int id, string text) {
foreach (var item in list) {
if (item.ID == id) {
return;
}
}
list.Add(new T(id, text)); // STOP HERE
// Cannot create an instance of the variable type 'T'
// because it does not have the new() constraint
}
public T this[int index] {
get {
if ((-1 < 0) && (index < list.Count)) {
return list[index];
}
return null;
}
}
public T Pull(int id) {
foreach (var item in list) {
if (item.ID == id) {
return item;
}
}
return null;
}
public T Pull(string status) {
foreach (var item in list) {
if (item.Text == status) {
return item;
}
}
return null;
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator() {
foreach (var item in list) yield return item;
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
return list.GetEnumerator();
}
#endregion
}
Visual Studio's IntelliSence wants me to add list.Add(T item), but I need to create this first.
I have attempted to re-write the offending line list.Add(new T(id, text)); as list.Add(new IdText(id, text));, but then I am reprimanded with the message "cannot convert from IdText to T".
How exactly do I get around this?
Next: When I go in to actually create a version of this IdText class later, I am not sure how exactly I can use this new class in the TCollection class I have designed for it.
For example, given this derived class:
public class ManufacturedPart : IdText {
public ManufacturedPart(int id, string partNum, string description)
: base(int id, string partNum) {
Description = description;
}
public string Description { get; private set; }
}
...would I need to also derive a special version of TCollection to accompany it, like so?
public class ManufacturedParts<T> : IEnumerable<T> where T : ManufacturedPart {
// OK, now I'm lost! Surely this can't be right!
}
1) You could use the new() constraint, make your properties public and add a parameterless constructor:
public class IdText
{
public IdText()
{
}
public IdText(int id, string text)
{
ID = id;
Text = text;
}
public int ID { get; set; }
public string Text { get; set; }
}
public class TCollection<T> : IEnumerable<T> where T : IdText, new()
{
private List<T> list;
public TCollection()
{
list = new List<T>();
}
public void Add(int id, string text)
{
foreach (var item in list)
{
if (item.ID == id)
{
return;
}
}
list.Add(new T { ID = id, Text = text });
}
}
2) You have multiple options:
If you want your collection to store any IdText (ManufacturedPart or anything else that derived from IdText):
TCollection<IdText> ss = new TCollection<IdText>();
The above, for now, can only store IdText as you instantiate objects in the Add(int, string) method, but if you provide a Add(T object) method, it could store any IdText instance.
If you want your collection to only contains ManufacturedParts:
public class ManufacturedParts<T> : TCollection<T> where T : ManufacturedPart, new()
{
// Provide here some specific implementation related to ManufacturedParts
// if you want. For example, a TotalPrice property if ManufacturedPart
// has a Price property.
}
TCollection<ManufacturedPart> ss2 = new ManufacturedParts<ManufacturedPart>();
or even simpler, if your collection doesn't provide any additional method depending on the type of the stored objects:
TCollection<ManufacturedPart> ss2 = new TCollection<ManufacturedPart>();
Even simpler, if your goal is to only store objects, a custom collection isn't needed:
List<IdText> ss2 = new List<IdText>(); // Uses the built-in generic List<T> type
About the first question: c# doesn't support constructors with parameters as a generic constrain. Something you can do is replace it with
(T)Activator.CreateInstance(typeof(T),new object[]{id,text});
By the other hand... you don't actually know how the constructors of the derived class will look like, so you can't ensure they will have that constructor.
About the second question, you can do this:
var collection = new TCollection<ManufacturedPart>();
in the same way List works.
Hope it helps.
If your collection class will be responsible for instantiating elements of its collected type, then you probably don't want to be using either the new() constraint or Activator.CreateInstance() -- as Jon Skeet has blogged, both of these exhibit poor performance.
It sounds like what you actually want is a provider delegate, like so:
public class MyCollection<T> : IEnumerable<T> where T : IdText {
private readonly List<T> list;
private readonly Func<int, string, T> provider;
public MyCollection(Func<int, string, T> provider) {
this.list = new List<T>();
this.provider = provider;
}
public void Add(int id, string text) {
list.Add(provider(id, text));
}
}
And then you'd use it like:
var collection = new MyCollection((id, text) => new ManufacturedPart(id, text));
You can think of this as passing the specific constructor you want to use as an argument into the class, which it then uses to construct instances as needed.
And you don't need to create a separate subclass for MyCollection<ManufacturedPart> -- just use the generic class directly.
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.
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
}