Populating a TreeView from a Tree<T> object - c#

I need to show a Tree<T> hierarchy in a TreeView, differentiating between the tree nodes and the tree leaves.
The Tree object is constructed at run time and there is no knowledge of its depth. Not a binary tree.
This is the DataTree class:
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;}
.....
.....
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<TreeNode<T>> GetEnumerator()
{
yield return this;
foreach (var directChild in this.Children)
{
foreach (var anyChild in directChild)
yield return anyChild;
}
}
}
And this is the code to populate the TreeView:
public void CreateTreeView()
{
AttributesTreeView=new TreeView();
foreach(TreeNode<string> entry in NewAttTree)
{
if(entry.Children.Count>0)
{
int tn=AttributesTreeView.Nodes.Add(new TreeNode(entry.Data.ToString().Replace("|",string.Empty)));
foreach(TreeNode<string> str in entry.Children)
{
if(tn!=0)
{
int itn=AttributesTreeView.Nodes[tn].Nodes.Add(new TreeNode(str.Data.ToString()));
}
}
}
}
}

What you're doing here is taking one tree, and projecting each node in that tree into something else, while maintaining the structure of that tree. This is actually fairly simple. Simply create a lookup that maps each node to all of its children, and then go through each of your nodes, look up "yourself" and then add all of the children from the lookup to your new node:
var roots = new TreeNode<string>[] { }; //the original data to map
var lookup = roots.SelectMany(node => node)
.ToLookup(node => node.Parent, node => new
{
node,
UINode = new TreeNode(node.Data),
});
foreach (var pair in lookup.SelectMany(group => group))
foreach (var child in lookup[pair.node])
pair.UINode.Nodes.Add(child.UINode);
TreeView view = new TreeView();
foreach (var root in lookup[null]) //assume nodes with a null parent are roots
view.Nodes.Add(root.UINode);

I can think of three ways to load a subset of the DataTreeNode structure:
Filtering: create a new DataTreeNode structure from the old structure, excluding subtrees that contain unwanted leaf nodes. Load the result.
Add a property to DataTreeNode that represents the range of values in its subtrees' leaf nodes, like a Huffman tree. Then on load, check the property before adding a given DataTreeNode.
For each DataTreeNode create a TreeNode, but discard the TreeNode if its subtrees' leaf nodes don't match the required values.
Below is pseudocode for option 3, using a HashSet to look up the required leaf node values.
void LoadDataTreeNode(TreeView treeView, DataTreeNode<T> dataTreeNode, HashSet<T> hashSet)
{
treeView.Nodes.Clear();
LoadDataTreeNode(treeView.Nodes, dataTreeNode, hashSet);
}
bool LoadDataTreeNode(TreeNodeCollection treeNodes, DataTreeNode<T> dataTreeNode, HashSet<T> hashSet)
{
bool result = hashSet.Contains(dataTreeNode.Data);
if (result)
{
var treeNode = new TreeNode(dataTreeNode.Data.ToString());
// Use this treeNode if at least one of its subtrees contains
// the required leaf node values. Assume that all other
// subtrees will be discarded by the relevant recursive calls.
result = false;
foreach (var child in dataTreeNode.Children)
{
if (LoadDataTreeNode(treeNode.Nodes, child, hashSet))
{
result = true;
}
}
if (result)
{
treeNodes.Add(treeNode);
}
}
return result;
}

OK, got it.
TreeNode newNode=new TreeNode("SEARCH");
AttributesTreeView.Nodes.Add(newNode);
CreateTreeView(NewAttTree,newNode);
public void CreateTreeView(DataTreeNode<string> root, TreeNode parentNode)
{
foreach(DataTreeNode<string> node in root.Children)
{
try
{
TreeNode newNode=new TreeNode(node.Data.ToString());
parentNode.Nodes.Add(newNode);
CreateTreeView(node,newNode);
}
catch (System.Exception e)
{
}
}
#groverboy: thanks for the push in the right direction.
One more question which presents itself:
How can we scan the DataTree structure and populate the TreeView only with the nodes that have leaves of certain value[s]. I mean in a DFT traversal, how can we decide to add a node before visiting the leaves and deciding if and which fit the filter criteria?

#groverboy: I tried your method but it didn't work and I noticed it won't ever get past the first if clause, unless the root DataTreeNode fits the bill, otherwise it returns without iterating the data tree at all.
Here is the method I came up with, based on your code: it works, but adds the same branch multiple times and I must be blind but I cant see why; maybe another pair of eyes.
bool PopulateTreeNode(DataTreeNode<string> dataNode,TreeNode treeNodes,string filter,bool ignoreCase)
{
if(dataNode.IsLeaf)
{
if(WcMatchExtensionMethods.WcMatches(dataNode.Data,filter,ignoreCase))
{
treeNodes.Nodes.Add(new TreeNode(dataNode.Data.ToString()));
return true;
}
else
return false;
}
bool result = false;
TreeNode treeNode=new TreeNode(dataNode.Data.ToString());
foreach (DataTreeNode<string> child in dataNode.Children)
{
if(PopulateTreeNode(child,treeNode,filter,ignoreCase))
{
treeNodes.Nodes.Add(treeNode);
result = true;
}
}
return result;
}

Related

C# Cannot Link nodes in a LinkedList

I am extending the C# double linked list as a means of creating a custom data structure for a rule engine algorithm I am working on. Unfortunately, the elements in the linked list after instantiation are never actually linked:
public abstract class DependencyTree<TTreeLeaf,TTreeLeafNode>
: LinkedList<LinkedListNode<TTreeLeaf>>
where TTreeLeaf : DependencyTreeLeaf
where TTreeLeafNode : DependencyTreeLeafNode
{
#region Constructors
public DependencyTree(ICollection<TTreeLeaf> leaves)
{
foreach (var leaf in leaves)
{
AddLast(new LinkedListNode<TTreeLeaf>(leaf));
}
var y = this.Where(node => node.Next != null || node.Previous != null).Count();
Console.WriteLine(y.ToString());
}
#endregion Constructors
The above always returns 0, no matter how many Leaves I pass in.
What is the correct way to insure that my leaves are actually linked? I'd rather not roll yet another custom data structure when .NET already has it available. Any tips are much appreciated.
*****EDIT*****
//Addition of DependencyLeaf definition
public abstract class DependencyTreeLeaf
: LinkedList<LinkedListNode<DependencyTreeLeafNode>>
{
#region Constructors
public DependencyTreeLeaf(IEnumerable<DependencyTreeLeafNode> leafNodes, DependencyState siblingDependency = DependencyState.Unset, IEnumerable<DependencyTreeLeaf> children = null, DependencyState childDependency = DependencyState.Unset)
{
foreach (var leaf in leafNodes)
{
AddLast(new LinkedListNode<DependencyTreeLeafNode>(leaf));
}
if (children != null)
{
Children = new LinkedList<LinkedListNode<DependencyTreeLeaf>>();
foreach (var childLeaf in children)
{
Children.AddLast(new LinkedListNode<DependencyTreeLeaf>(childLeaf));
}
}
SiblingForwardDependency = siblingDependency;
ChildDownwardDependency = childDependency;
}
}
you are adding your own linkedlist nodes, you don't need to do this, the linked list will do this. You are adding those LinkedListNodes into the actual LinkedListNodes, hence, your ones don't have any previous or next being maintained. However, the problem you are facing is the IEnumerable will iterate over TTreeLeaf and not nodes.
If you want to iterate over the Nodes themselves then you need something like :-
public class DependencyTree<TTreeLeaf, TTreeLeafNode>
: LinkedList<TTreeLeaf>
where TTreeLeaf : DependencyTreeLeaf
where TTreeLeafNode : DependencyTreeLeafNode
{
public DependencyTree(ICollection<TTreeLeaf> leaves)
{
foreach (var leaf in leaves)
{
AddLast(leaf);
}
var y = this.Nodes().Count(node => node.Next != null || node.Previous != null);
Console.WriteLine(y.ToString());
}
public IEnumerable<LinkedListNode<TTreeLeaf>> Nodes()
{
var node = this.First;
while (node != null)
{
yield return node;
node = node.Next;
}
}
}
you can of course just go this.Count();

C# Putting non-hierarchical CSV data into hierarchy

We have a 3rd party workflow system that contains a hierarchical list of actions which is stored as flat file in the following format:
Root
Root-Node1
Root-Node1-Node1
Root-Node1-Node2
Root-Node1-Node2-Node1
Root-Node1-Node2-Node1-Node1
Root-Node1-Node2-Node1-Node2
Root-Node2
Root-Node2-Node1
etc...
Under each node is a list of properties and the aim of this project is to write a small program that will iterate through each file, build a hierarchy from the Root-Node relationships and then we will able to use this model to run reports on the data.
My attempt so far has been to create a Node class, containing a Child property of type List<Node> which will store the hierarchy
I am struggling to figure out how to determine which Node should be the child of which node. My current process is to capture the previous node name and if the current node name contains the previous node name, it must be a child, but I found this to be flakey when it gets a few nodes deep.
Does anyone have any suggestions for a more reliable way to describe these relationships?
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.

Graph Adjacency List C#

I am fairly new to programming in C# and am currently attempting to write the generic classes Graph and GraphNode which I have included below. I understand the logistics behind the methods IsAdjacent and GetNodeByID however I am not to sure how to code these correctly in C# so I have included a small bit of psuedo code in these methods. This however is not the case with the AddEdge method. If possible could you provide me with a solution to these three methods.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Graph
{
public class GraphNode<T>
{
private T id; //data stored in graph
private LinkedList<T> adjList; //adjacency list
//constructor
public GraphNode(T id)
{
this.id = id;
adjList = new LinkedList<T>();
}
//add an edge from this node : add to to the adjacency list
public void AddEdge(GraphNode<T> to)
{
adjList.AddFirst(to.ID);
}
//set and get for ID – data stored in graph
public T ID
{
set { id = value; }
get { return id; }
}
//returns adjacency list – useful for traversal methods
public LinkedList<T> GetAdjList()
{
return adjList;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Graph
{
public class Graph<T> where T : IComparable
{
//list of GraphNodes in this graph
private LinkedList<GraphNode<T>> nodes;
//constructor - set nodes to new empty list
public Graph()
{
nodes = new LinkedList<GraphNode<T>>();
}
//only return true if the graph’s list of nodes is empty
public bool IsEmptyGraph()
{
return nodes.Count == 0;
}
//Search through list of nodes for node
//Node will be a new graphnode with the
// containing the ID to be search for
public bool ContainsGraph(GraphNode<T> node)
{
//search based on ID
foreach (GraphNode<T> n in nodes)
{
if (n.ID.CompareTo(node.ID) == 0)
return true;
}
return false;
}
//find from in list of nodes and search its adjList for to
public bool IsAdjacent(GraphNode<T> from, GraphNode<T> to)
{
foreach(GraphNode<T> n in nodes)
{
if (n.ID same as from.ID)
{ if (from.AdjList contains to.ID)
return true;
}
return false;
}
}
//add a new graphNode to list of nodes
public void AddNode(T id)
{
GraphNode<T> n = new GraphNode<T>(id);
nodes.AddFirst(n);
}
//Search through list of nodes for node with this ID
public GraphNode<T> GetNodeByID(T id)
{
foreach( GraphNode<T> n in nodes )
{
if (id = n.ID)
{
return n;
}
}
return null;
}
//find from in list of nodes (look at other methods)
//and call graphNode method to add an edge to to
//think about validation here
public void AddEdge(T from, T to)
{
}
//perform a DFS traversal starting at startID, leaving a list
//of visitied ID’s in the visited list.
}
}
Many Thanks
A couple of notes:
A few of your methods take the node "ID" rather than the node itself. Wouldn't it be easier just to use the node?
Any good reason for using LinkedList rather than List for most of these items? There's an SO discussion about this here and it's not obvious what LinkedList brings to your implementation.
With adjacency lists, your AddEdge function needs to take two inputs: your source node, and destination node, and add them to each others' adjacency lists. You already have a function AddEdge in your Node class which adds a vertex to its adjacency list. So, your code will look something like this:
public void AddEdge(GraphNode source, GraphNode destination)
{
source.AddEdge(destination);
destination.AddEdge(source);
}
For isAdjacent, I'm not clear on why you need to search the entire list of nodes. You just need to check that one node is in the others' adjacency list (which should imply vice versa assuming it's coded correctly):
public bool isAdjacent(GraphNode source, GraphNode destination)
{
if (source.AdjList.Contains(destination))
{
return true;
}
return false;
}
I haven't answered your question about GetNodeByID because of my above note - I'm not sure why it's done by ID rather than by the node itself. However, I don't see a problem with your method if you really want to do it with IDs (although it should be if (id = n.ID) rather than if (id = n.ID)).

Counting descendants in a tree

I have the following class which recurs on itself to form a tree-like data structure:
public class chartObject
{
public string name { get; set; }
public int descendants { get; set; }
public List<chartObject> children { get; set; }
}
For each object in the tree I would like to populate the descendant property with the amount objects that exist underneath it.
Example structure:
chartObject1 (descendants: 4)
└-chartObject2 (descendants: 0)
└-chartObject3 (descendants: 2)
└--chartObject4 (descendants: 1)
└---chartObject5 (descendants: 0)
What would be the most efficient way of doing this?
How about the recursive formula:
children.Count + children.Sum(c => c.descendants)
This is suitable for eager-evaluation / caching if the tree is immutable (which it isn't from the class declaration). If you want efficiency even in the face of mutability, you'll find this a lot more difficult; you can consider marking parts of the tree "dirty" as it is mutated / eagerly force the re-evalutation of this metric to "bubble up" as part of a tree is mutated.
This works for me:
public void SetDescendants(chartObject current)
{
foreach (var child in current.children)
{
SetDescendants(child);
}
current.descendants = current.children.Sum(x => 1 + x.descendants);
}
I tested with this code:
var co = new chartObject()
{
name = "chartObject1",
children = new List<chartObject>()
{
new chartObject()
{
name = "chartObject2",
children = new List<chartObject>() { }
},
new chartObject()
{
name = "chartObject3",
children = new List<chartObject>()
{
new chartObject()
{
name = "chartObject4",
children = new List<chartObject>()
{
new chartObject()
{
name = "chartObject5",
children = new List<chartObject>() { }
}
}
}
}
}
}
};
And got this as the result:
For calculations to be most efficient, cache their result in the node itself. Otherwise, you'll be re-calculating the count every time the descendants property is looked up.
The cost of doing that is the need to invalidate the cache all the way up the parent chain, like this:
public class chartObject
{
private chartObject _parent;
private int? _descCache = null;
public string name { get; set; }
public int descendants {
get {
return _descCache ?? calcDescendents();
}
}
public List<chartObject> children { get; set; }
public void AddChild(chartObject child) {
child._parent = this;
children.Add(child);
chartObject tmp = this;
while (tmp != null) {
tmp._descCache = null;
tmp = tmp._parent;
}
}
private int calcDescendents() {
return children.Count+children.Sum(child => child.descendants);
}
}
Walk all nodes of the tree (depth first is ok) and when done with children set "descendants property to sum of children's descendants + child count. You have to do it on every change to the tree structure. You should be able to limit updates only to parents of element that is changed.
If nodes made immutable you can populate the field at creation time.
Side notes:
Your tree is mutable as it is now (one can easily add more child nodes anywhere), so it may be safer to have method that counts descendants instead of property on a node.
Having computed property int descendants { get; set; } to be read/write is confusing as anyone can set its value to whatever number. Consider if making it read only and updating when one of child nodes changes (requires some custom notification mechanism).
Code style - consider naming classes with upper case names for code that is intended to be public (follow Microsoft's C# coding guidelines). chartObject -> ChartObject

Simple Linked List C# AddAfter method

Im working with simple linked lists in C# and I have no idea how to add elements at the end of the list, colud anyone helpme?
namespace ConsoleApplication1
{
class Class1
{
public class Node()
{
public int Data;
public Node Next;
}
private Node FirstNode=null;
public void AddBefore(int number)
{
Node NewNode=new Node();
NewNode.Next=FirstNode;
NewNode.Data=number;
FirstNode=NewNode;
}
public void AddAfter(int number)
{
if (FirstNode==null)
{
AddBefore(number);
}
else
{
???????????????
}
}
}
}
You need to iterate through your list until you find the last node, and then add it to the end. Something like:
public void AddAfter(int number)
{
if (FirstNode==null)
{
AddBefore(number);
}
else
{
// Finding the last node
Node currentNode = FirstNode;
while (currentNode.NextNode != null)
currentNode = currentNode.NextNode;
// Constructing a new node
Node newNode = new Node();
newNode.Data = number;
newNode.Next = null;
// Adding the new node to the end
currentNode.NextNode = newNode;
}
}
else
{
Node NewNode=new Node();
NewNode.Data=number;
Node LastNode = GetLastNode();
LastNode.Next = NewNode;
}
You'll still have to implement GetLastNode or else you wont practise anything =P
The question is kind of confusing. Are you asking how to place a node at the end of the list, or as the next item in the list.
I had to do this for a homework assignment way back in the day (it was java though). If you want to always add a node to the end of the list then you also need to edit your list class to contain a head and tail of the list. This will allow you to add items to the end or beginning.
If you want to always add a node to the end then you could try editing the code so that when you add a node to the end the previous node's next node value will be set to the tail instead of null. This will always allow for you to add an item to the end of the list (which is what most add methods do unless a position is specified anyways)
In short:
Add Node tailNode = null; to Class and add a method that will get and set the next node for the Node class. Once this is done, then edit the code so that it looks something like this:
class Class1
{
public class Node()
{
public int Data;
public Node Next;
//Class to set next node
public void setNext(Node nextNode)
{
//Set next node
Next = nextNode;
}
//Get next node
public Node getNext()
{
return Next;
}
}
private Node FirstNode=null;
private Node lastNode = null;
public void AddBefore(int number)
{
Node NewNode=new Node();
NewNode.Next=FirstNode;
NewNode.Data=number;
FirstNode=NewNode;
}
public void AddAfter(int number)
{
if (FirstNode==null)
{
AddBefore(number);
}
else
{
if(FirstNode.getNext() == null)
{
//No tail. Make this node tail
lastNode = new Node();
lastNode.Data = number;
//Set first node's next to last node
FirstNode.setNext(lastNode);
}else{ //TailNode already set
//New node to be tail
Node newLastNode = new Node();
newLastNode.Data = number;
//Set the current tail node to have this node as next
lastNode.setNext(newLastNode);
//Make new last node last node
lastNode = newLastNode;
}
}
}
}
The code may be a little off (I haven't really tested it) but that is the main picture of what you are going to have to do.

Categories

Resources