Dynamic derive Generic Type Parameter - c#

I am using a recursive function for a object tree. That is, my object collection is like:
Object1
--Object2
----Object3
------Object4
All objects inherits from a base object (abstract class), where has a Validate() method, and its collection inherits from ITreeCollection. I have written a recursive function to perform that:
private bool Validate<T>(ITreeCollection items) where T : TreeNodeBase
{
foreach (var itm in items as Collection<T>)
{
if (((TreeNodeBase)itm).Items != null)
{
return Validate<T>(((TreeNodeBase)itm).Items);
}
else return true;
}
return true;
}
How can I derive the the type parameter T for the inner function (i.e. return Validate<T>(((TreeNodeBase)itm).Items))

Firstly, as it stands, you are not using the type parameter T so it could safely be removed. However I imagine you might want to do some type specific validation so this is perhaps not that helpful a suggestion. But, without example of what you want to do with T it's difficult to make suggestions.
Anyhow, here's one approach of what I think you are trying to do:
private bool Validate(ITreeCollection items)
{
foreach (TreeNodeBase node in (IEnumerable) items)
{
// validate the node itself first
if (!Validate(node))
{
return false;
}
if (node.Items != null)
{
// validate its children
if (!Validate(node.Items)
{
return false;
}
}
}
return true;
}
private bool Validate(TreeNodeBase node)
{
if (node is BananaNode)
{
var bananaNode = (BananaNode) node;
//TODO do BananaNode specific validation
}
else if (node is AppleNode)
{
var appleNode = (AppleNode) node;
//TODO do AppleNode specific validation
}
else
{
throw new ArgumentOutOfRangeException("Cannot validate node of type '" + node.GetType().Name + "'.");
}
}
You could get snazzy with the dynamic keyword and get rid of some of this type checking but it does get a bit confusing and I'd advise against it:
private bool Validate(ITreeCollection items)
{
foreach (TreeNodeBase node in (IEnumerable) items)
{
// validate the node itself first
if (!Validate((dynamic) node)) // this will call the most appropriate version of Validate
{
return false;
}
if (node.Items != null)
{
// validate its children
if (!Validate(node.Items)
{
return false;
}
}
}
return true;
}
private bool Validate(BananaNode node)
{
//TODO do BananaNode specific validation
}
private bool Validate(AppleNode node)
{
//TODO do AppleNode specific validation
}
private bool Validate(TreeNodeBase node)
{
throw new ArgumentOutOfRangeException("Cannot validate node of type '" + node.GetType().Name + "'.");
}

Related

Mapping binary search tree

I have this binary search tree with Node class and I need to write mapping and filtering method for it but I have no clue how can I go through the whole tree. My every attempt to go through it skipped almost half of the tree.
public class BST<T> where T:IComparable<T>
{
public class Node
{
public T value { get; }
public Node left;
public Node right;
public Node(T element)
{
this.value = element;
left = null;
right = null;
}
}
private Node root;
private void add(T element)
{
if (root == null)
root = new Node(element);
else
{
add(element, root);
}
}
public void add(T element, Node leaf)
{
if(element.CompareTo(leaf.value) > 0)
{
if (leaf.right == null)
leaf.right = new Node(element);
else
add(element,leaf.right);
}
else
{
if (leaf.left == null)
leaf.left = new Node(element);
else
add(element, leaf.left);
}
}
}
I have no clue how can I go through the whole tree
There are many ways to do that. One is to make your class iterable.
For that you can define the following method on your Node class:
public IEnumerator<T> GetEnumerator()
{
if (left != null) {
foreach (var node in left) {
yield return node;
}
}
yield return value;
if (right != null) {
foreach (var node in right) {
yield return node;
}
}
}
And delegate to it from a similar method on your BST class:
public IEnumerator<T> GetEnumerator()
{
if (root != null) {
foreach (var node in root) {
yield return node;
}
}
}
Now you can write code like this:
var tree = new BST<int>();
tree.add(4);
tree.add(2);
tree.add(3);
tree.add(6);
tree.add(5);
foreach (var value in tree) {
Console.WriteLine(value);
}
I need to write mapping and filtering method for it
It depends on what you want the result of a mapping/filtering function to be. If it is just a sequence of values, the above should be simple to adapt. If a new tree should be created with the mapped/filtered values, then feed these values back into a new tree (calling its add), or (in case of mapping) use the same recursive pattern of the above methods to create a new method that does not do yield, but creates a new tree while iterating the existing nodes, so the new tree has the same shape, but with mapped values.

Mixed-Type Generic C# Stack (Linked List Implementation)

I realize that in most cases, it would be beneficial to have a homogeneous, type-safe stack, but I'm curious if this is possible, as I was asked to create a Stack for an exercise which accepts all types.
So I currently have a generic linked-list Stack class, and I'm wondering if there's any way to make the Node class generic so that the Next node can be of a different type. I know I can make the stack accept all types by just making the all the type parameters object instead of using a generic, but I was warned of the performance implications of boxing & unboxing of value types / upcasting all of it's elements to the base object class.
So I went ahead an implemented it as Generic, but was unable to find a solution that allowed different types for each Node. If I wanted to avoid the object approach, is there a possible solution? Even if it takes a different approach altogether, it doesn't necessarily have to fit this approach.
I hope this makes sense! At any rate, here's the implementation I currently have. Please let me know what you think.
Node.cs
namespace DataStructures
{
class Node<T>
{
public T Value { get; private set; }
public Node<T> Next { get; set; }
public Node(T value)
{
Value = value;
}
}
}
Stack.cs
namespace DataStructures
{
class Stack<T>
{
private Node<T> root;
public int Size { get; private set; } = 0;
public Stack()
{
}
public Stack(params T[] values)
{
foreach (var value in values)
Push(value);
}
public void Push(T value)
{
if (value == null)
throw new ArgumentNullException("value", "You cannot push a null value onto the stack");
var newNode = new Node<T>(value);
if (root != null)
newNode.Next = root;
root = newNode;
Size++;
}
public dynamic Peek()
{
if (root == null)
return null;
return root.Value;
}
public T Pop()
{
if (root == null)
throw new InvalidOperationException("The stack is empty, nothing to pop");
Size--;
var popped = root.Value;
root = root.Next;
return popped;
}
public bool TryPop(out dynamic popped)
{
if (root == null)
{
popped = null;
return false;
}
else
{
popped = Pop();
return true;
}
}
public bool IsEmpty() => root == null ? true : false;
public void Clear()
{
root = null;
}
}
}

How to comply DRY principle if two functions are almost the same?

I have two functions which are almost the same. Is there a good way to remove duplicates?
I think about moving duplicated code in the separate function and pass a function as the argument.
private object GetValue(object key)
{
var index = GetHash(key);
var node = _table[index];
while (node != null)
{
if (Equals(node.Key, key)) return node.Value;
node = node.Next;
}
throw new KeyNotFoundException("Such key doesn't exist");
}
private void SetValue(object key, object value)
{
var index = GetHash(key);
var node = _table[index];
if(value == null) RemoveValue(key);
while (node != null)
{
if (Equals(node.Key, key))
{
node.Value = value;
return;
}
node = node.Next;
}
throw new KeyNotFoundException("Such key doesn't exist");
}
Sure, seems reasonable.
private Node GetNode(object key)
{
var index = GetHash(key);
var node = _table[index];
while (true)
{
if (node == null)
throw ...
if (Equals(node.Key, key))
return node;
node = node.Next;
}
}
private object GetValue(object key) => GetNode(key).Value;
private void SetValue(object key, object value)
{
if (value == null)
RemoveValue(key);
else
GetNode(key).Value = value;
}
Now, always ask yourself "how can I improve this further?" Some thoughts:
Why are these methods private? Are they implementation details of a nice public API, with a proper indexer?
Object, in 2018? Use generics!
And so on.
Split each of your methods in two parts:
Finding the target node (private helper), and
Doing something to the target node if it exists
Finding the target node should have this signature:
private Node FindNodeByKey(object key) {
...
}
This method would be in charge of throwing KeyNotFoundException, so both getter and setter could assume that when FindNodeByKey returns a value, it is not null. This assumption lets you reduce the getter to a single line:
private object GetValue(object key) {
return FindNodeByKey(key).Value;
}
private void SetValue(object key, object value) {
if (value == null) {
RemoveValue(key);
} else {
FindNodeByKey(key).Value = value;
}
}

Iterating through a Tree and getting certain children in C#

I'm currently working with a tree structure defined like this
public class TreeNode
{
private ObservableCollection<TreeItem> nodeItems;
private ObservableCollection<TreeNode> nodeChildren;
//public "NodeItems" and "NodeChildren" getters and setters
}
public class TreeItem
{
private bool isSelected;
private string Name;
//public "IsSelected" and "Name" getters and setters
}
public class Tree
{
private TreeNode rootNode;
//public getters and setters properties
}
and I'm trying to write a function or a public property that recursively gets all the nodeItems in the Tree that have isSelected == true and make it a flat collection.
So I wrote this function in the TreeNode class, that recursively navigates through the children:
public ObservableCollection<TreeItem> SelectedItems()
{
ObservableCollection<TreeItem> tempCollection = new ObservableCollection<TreeItem>();
if (nodeItems != null)
{
foreach (TreeItem item in nodeItems)
{
if (item.IsSelected == true)
{
tempCollection.Add(item);
}
}
}
if (nodeChildren != null)
{
foreach (TreeNode node in nodeChildren)
{
tempCollection.Concat(node.SelectedItem());
}
}
return tempCollection;
}
but it always returns an empty collection at the end.
How can I correct it, and maybe improve it (by using a Lambda expression or a property)?
The Concat function on the ObservableCollection does not modify any of the arguments. You have to assign the resulting object to your tempCollection.
if (nodeChildren != null)
{
foreach (TreeNode node in nodeChildren)
{
tempCollection = new ObservableCollection<TreeNode>(tempCollection.Concat(node.SelectedItem()));
}
}
EDIT: Alternatively, you can use an overloaded private method to not use so many temporary collections:
public ObservableCollection<TreeItem> SelectedItems()
{
ObservableCollection<TreeItem> toReturn = new ObservableCollection<TreeItem>();
SelectedItems(toReturn);
return toReturn;
}
private void SelectedItems(ObservableCollection<TreeItem> tempCollection)
{
if (nodeItems != null)
{
foreach (TreeItem item in nodeItems)
{
if (item.IsSelected == true)
{
tempCollection.Add(item);
}
}
}
if (nodeChildren != null)
{
foreach (TreeNode node in nodeChildren)
{
node.SelectedItems(tempCollection);
}
}
}
You can simplify your definition of a tree down to this:
public class Tree : ObservableCollection<Tree>
{
public ObservableCollection<TreeItem> nodeItems;
}
Now you can do this:
public IEnumerable<TreeItem> FlattenIsSelected(Tree tree)
{
return tree.nodeItems.Where(x => x.isSelected)
.Concat(tree.SelectMany(t => FlattenIsSelected(t)));
}
It's not much more difficult if you keep your current definitions.

Traversing a Tree Structure

I am trying to understand how to traverse a tree data structure, and I am having a problem doing it, especially as I am trying to use IEnumerable. I want the tree as a dictionary so I can refer to the nodes by their string names. The tree will hold different class objects but as these objects all implement an interface IMyInterface, type of the tree will be the IMyInterface interface.
I have the tree:
internal class Tree<T>
{
private TreeNode<T> root;
internal Tree(T value)
{
if (value == null)
{
throw new ArgumentNullException(
"Cannot use a null value to construct a tree.");
}
this.root = new TreeNode<T>(value);
}
internal Tree(T value, params Tree<T>[] children) : this(value)
{
foreach (Tree<T> child in children)
{
this.root.AddChild(child.root);
}
}
internal TreeNode<T> Root
{
get { return this.root; }
}
private void PrintDFS(TreeNode<T> root, int spaces)
{
if (spaces < 0)
{
throw new ArgumentOutOfRangeException(
"The number of spaces used to represent the parent-child relation in a tree must be greater than or equal to zero.");
}
if (this.root == null)
{
return;
}
StringBuilder sb = new StringBuilder();
sb.Append(' ', spaces);
sb.Append(root.Value);
TreeNode<T> child = null;
foreach (Tree<T> child in this.root) // <--- this generates an error
{
PrintDFS(child, spaces);
}
}
// Traverses and prints the tree in
// Depth-First Search (DFS) manner
internal void TraverseDFS()
{
this.PrintDFS(this.root, 0);
}
}
And my node class is:
internal class TreeNode<T> : IEnumerable<TreeNode<T>>
{
private T value;
private bool hasParent;
private readonly Dictionary<string, TreeNode<T>> children = new Dictionary<string, TreeNode<T>>();
internal TreeNode(T value)
{
if (value == null)
{
throw new ArgumentNullException(
"Cannot insert null values for a tree node!");
}
this.value = value;
this.children = new Dictionary<string, TreeNode<T>>(); // dictionary that holds the children of each node
}
internal T Value
{
get { return this.value; }
set { this.value = value; }
}
internal int ChildrenCount
{
get
{
return this.children.Count;
}
}
internal void AddChild(TreeNode<T> child)
{
if (child == null)
{
throw new ArgumentNullException(
"Cannot insert null value as child node.");
}
if (child.hasParent)
{
throw new ArgumentException(
"The child node already has a parent.");
}
child.hasParent = true;
this.children.Add(child.ToString(), child);
}
internal TreeNode<T> GetChild(string nodeName)
{
return this.children[nodeName];
}
internal IEnumerator<TreeNode<T>> GetEnumerator()
{
return this.children.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
IEnumerator<TreeNode<T>> IEnumerable<TreeNode<T>>.GetEnumerator()
{
throw new NotImplementedException();
}
}
The issue seems to be the code:
foreach (Tree<T> child in this.root) // <--- this generates an error
{
PrintDFS(child, spaces);
}
(Code snippet from the Tree class) Any suggestions would be greatly appreciated.
EDIT
I get the error messages:
Error 669 A local variable named 'child' cannot be declared in this scope because it would give a different meaning to 'child', which is already used in a 'parent or current' scope to denote something else.
Error 672 Cannot convert type TreeNode<T> to Tree<T>
And the warning message:
Warning 668 TreeNode<T> does not implement the 'collection' pattern. TreeNode<T>.GetEnumerator() is either static or not public.
Issue #1
Error 669 A local variable named 'child' cannot be declared in this
scope because it would give a different meaning to 'child', which is
already used in a 'parent or current' scope to denote something else.
TreeNode<T> child = null;
foreach (Tree<T> child in this.root) // <--- this generates an error
{
PrintDFS(child, spaces);
}
You already have a child variable. You need to name them differently. The error is pretty self explanatory.
For this situation, just remove child from above the foreach since it is useless there.
foreach (var child in this.root)
{
PrintDFS(child, spaces);
}
I think you wanted TreeNode<T>, but not sure what was supposed to actually return out of root.
Issue #2
Error 672 Cannot convert type TreeNode to Tree
If you're supposed to be looping over TreeNode<T>, not Tree<T> as the error states. Just use var unless you are actually trying to iterates trees and not nodes.
Issue #3
Warning 668 TreeNode does not implement the 'collection' pattern. TreeNode.GetEnumerator() is either static or not public.
It needs to be public. Internal does not cut it because it needs to adhere to the IEnumerable contract. Looks like you have that solved though with the explicit implementation of it.
First, replace your 3 GetEnumertor functions with these 2:
public IEnumerator<TreeNode<T>> GetEnumerator()
{
return this.children.Values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
Then change the last part of your PrintDFS loop as follows:
//TreeNode<T> child = null;
foreach (var child in this.root)
{
PrintDFS(child, spaces);
}
That compiles.

Categories

Resources