Iterating through a Tree and getting certain children in C# - 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.

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.

Simplest way to Recurse Over Object Tree

I have a base class:
public abstract class BaseClass{
public bool IsSelected {get; set;}
}
A derived class with a collection representing a hierarchy:
public class DerivedOne : BaseClass{
public ObservableCollection<BaseClass> Children {get; set;}
}
Another derived class:
public class DerivedTwo : BaseClass{
}
What is the simplest way to find all of the elements under a DerivedOne root that have IsSelected set to true?
You left out some requirement detail, but I think something like this should work:
public IEnumerable<BaseClass> AllIsSelected(BaseClass root)
{
if (root.IsSelected)
{
yield return root;
}
var composite = root as DerivedOne;
if (composite != null)
{
foreach (var v in composite.Children)
{
foreach (var x in AllIsSelected(v))
{
yield return x;
}
}
}
}
Of course, if you want a full list all at once, you could build the list instead of using 'yield'.
This is the same design discussed here: IEnumerable and Recursion using yield return.
As another answer said, you can use LINQ to shorten this somewhat. This version avoids making the temporary list.
public IEnumerable<BaseClass> AllIsSelected(BaseClass root)
{
if (root.IsSelected)
{
yield return root;
}
var composite = root as DerivedOne;
if (composite != null)
{
foreach (var x in composite.Children.SelectMany(v => AllIsSelected(v)))
{
yield return x;
}
}
}
The simplest method would be to use LINQ with recursion
public IEnumerable<BaseClass> GetAllSelectedChildren(DerivedOne derivedOne)
{
return derivedOne.Children.SelectMany(GetAllSelected);
}
public IEnumerable<BaseClass> GetAllSelected(BaseClass baseClass)
{
var selected = new List<BaseClass>();
if(baseClass.IsSelected)
{
selected.Add(baseClass);
}
var derivedOne = baseClass as DerivedOne;
if(derivedOne != null)
{
selected.AddRange(GetAllSelectedChildren(derivedOne));
}
return selected;
}
Use simple Linq.
return root.Children
.SelectMany(c => new[]{ c }.Concat(c.Children)) // flatten the structure including self node.
.Where(e => e.IsSelected) // filter selected items
.ToList();

How to create a tree representing namespaces from their string representations

How can I create a tree-like data structure for the namespaces.
For example, for these namespaces:
Enums.NEWENUMS.NEW1
Enums.NEWENUMS.NEW2
Enums.NEWENUMS.NEW3
Enums.OLDENUMS
Enums.TEST.SUB
Enums.TEST.SUB.OK
And then load it into a treeview like shown below:
I tried to split the namespaces, but for the life of me I can't think of a logic to generate it correctly.
Also tried to generate it the way you generate a directory structure, but can't get my head around it since namespaces need splitting.
1. Parsing namespace
Here is the class that represents namespace. It represents namespace as a dictionary of directly nested namespaces. To generate Namespaces from strings it provides static methods that use recursive calls and LINQ:
public class Namespace : IDictionary<String, Namespace>
{
#region Static
public static IEnumerable<Namespace> FromStrings(IEnumerable<String> namespaceStrings)
{
// Split all strings
var splitSubNamespaces = namespaceStrings
.Select(fullNamespace =>
fullNamespace.Split('.'));
return FromSplitStrings(null, splitSubNamespaces);
}
public static IEnumerable<Namespace> FromSplitStrings(Namespace root, IEnumerable<IEnumerable<String>> splitSubNamespaces)
{
if (splitSubNamespaces == null)
throw new ArgumentNullException("splitSubNamespaces");
return splitSubNamespaces
// Remove those split sequences that have no elements
.Where(splitSubNamespace =>
splitSubNamespace.Any())
// Group by the outermost namespace
.GroupBy(splitNamespace =>
splitNamespace.First())
// Create Namespace for each group and prepare sequences that represent nested namespaces
.Select(group =>
new
{
Root = new Namespace(group.Key, root),
SplitSubnamespaces = group
.Select(splitNamespace =>
splitNamespace.Skip(1))
})
// Select nested namespaces with recursive split call
.Select(obj =>
new
{
Root = obj.Root,
SubNamespaces = FromSplitStrings(obj.Root, obj.SplitSubnamespaces)
})
// Select only uppermost level namespaces to return
.Select(obj =>
obj.Root)
// To avoid deferred execution problems when recursive function may not be able to create nested namespaces
.ToArray();
}
#endregion
#region Fields
private IDictionary<String, Namespace> subNamespaces;
#endregion
#region Constructors
private Namespace(String nameOnLevel, Namespace parent)
{
if (String.IsNullOrWhiteSpace(nameOnLevel))
throw new ArgumentException("nameOfLevel");
this.Parent = parent;
this.NameOnLevel = nameOnLevel;
this.subNamespaces = new Dictionary<String, Namespace>();
if (this.Parent != null)
{
this.Parent.Add(this.NameOnLevel, this);
}
}
private Namespace(String nameOfLevel)
: this(nameOfLevel, null)
{
}
#endregion
#region Properties
public String NameOnLevel
{
get;
private set;
}
public String FullName
{
get
{
if (this.Parent == null)
return this.NameOnLevel;
return String.Format("{0}.{1}",
this.Parent.FullName,
this.NameOnLevel);
}
}
private Namespace _Parent;
public Namespace Parent
{
get
{
return this._Parent;
}
private set
{
if (this.Parent != null)
this.Parent.Remove(this.NameOnLevel);
this._Parent = value;
}
}
#endregion
#region IDictionary implementation
public void Add(string key, Namespace value)
{
if (this.ContainsKey(key))
throw new InvalidOperationException("Namespace already contains namespace with such name on level");
this.subNamespaces.Add(key, value);
}
public bool ContainsKey(string key)
{
return this.subNamespaces.ContainsKey(key);
}
public ICollection<string> Keys
{
get { return this.subNamespaces.Keys; }
}
public bool Remove(string key)
{
if (!this.ContainsKey(key))
throw new KeyNotFoundException();
this[key]._Parent = null;
return this.subNamespaces.Remove(key);
}
public bool TryGetValue(string key, out Namespace value)
{
return this.subNamespaces.TryGetValue(key, out value);
}
public ICollection<Namespace> Values
{
get { return this.subNamespaces.Values; }
}
public ICollection<Namespace> Subnamespaces
{
get { return this.subNamespaces.Values; }
}
public Namespace this[string nameOnLevel]
{
get
{
return this.subNamespaces[nameOnLevel];
}
set
{
if (value == null)
throw new ArgumentException("value");
Namespace toReplace;
if (this.TryGetValue(nameOnLevel, out toReplace))
{
toReplace.Parent = null;
}
value.Parent = this;
}
}
public void Add(KeyValuePair<string, Namespace> item)
{
this.Add(item.Key, item.Value);
}
public void Clear()
{
foreach (var subNamespace in this.subNamespaces.Select(kv => kv.Value))
{
subNamespace._Parent = null;
}
this.subNamespaces.Clear();
}
public bool Contains(KeyValuePair<string, Namespace> item)
{
return this.subNamespaces.Contains(item);
}
public void CopyTo(KeyValuePair<string, Namespace>[] array, int arrayIndex)
{
this.subNamespaces.CopyTo(array, arrayIndex);
}
public int Count
{
get { return this.subNamespaces.Count; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(KeyValuePair<string, Namespace> item)
{
return this.subNamespaces.Remove(item);
}
public IEnumerator<KeyValuePair<string, Namespace>> GetEnumerator()
{
return this.subNamespaces.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
#endregion
#region Overrides
public override string ToString()
{
return this.FullName;
}
#endregion
}
P.S: This class may have few incorrectly implemented methods.
P.S.1: Parsing methods can be rewritten without LINQ. Actually this LINQ solution is not very idiomatic or a really good example of how and when to use LINQ. But it is short and mostly simple.
2. Adding namespaces to the TreeView
You haven't mentioned the UI framework you use, so I have defaulted to Windows Forms. Assuming that you have added TreeView named treeView_Namespaces to the form:
public Form1()
{
InitializeComponent();
var namespaceStrings = new String[]
{
"Enums.NEWENUMS.NEW1",
"Enums.NEWENUMS.NEW2",
"Enums.NEWENUMS.NEW3",
"Enums.OLDENUMS",
"Enums.TEST.SUB",
"Enums.TEST.SUB.OK"
};
var namespaces = Namespace.FromStrings(namespaceStrings);
AddNamespaces(this.treeView_Namespaces.Nodes, namespaces);
}
void AddNamespaces(TreeNodeCollection nodeCollection, IEnumerable<Namespace> namespaces)
{
foreach (var aNamespace in namespaces)
{
TreeNode node = new TreeNode(aNamespace.NameOnLevel);
nodeCollection.Add(node);
AddNamespaces(node.Nodes, aNamespace.Subnamespaces);
node.Expand();
}
}
3. If you need to generate such tree from real namespaces
To do that you will have to walk through types in the Assembly and get all their namespaces:
For example, this code get all types in the currently executing Assembly:
var namespaceStrings = Assembly
.GetExecutingAssembly()
.GetTypes()
.Select(type =>
type.Namespace)
.Where(#namespace =>
#namespace != null);

Depth first search using Queue

How do I do a depth first search using a Queue in c#?
The following is my datastructure:
public class Node
{
public string Name{get;set}
public IEnumerable<Node> Children{get;set;}
}
Now I have a collection of Node object each with children, which again has children and so on.
I want to access each node and convert it into a different form.
Something like the below:
public IEnumerable<IContent> BuildContentFrom(IEnumerable<Node> nodes)
{
var queue = new Queue<Node>(nodes);
while (queue.Any())
{
var next = queue.Dequeue();
yield return BuildContentFromSingle(next);
foreach (var child in next.Children)
{
queue.Enqueue(child);
}
}
}
public IContent BuildContentFromSingle(Node node)
{
var content = _contentFactory.Create(node);
return content;
}
The above does not give me depth first for some reason. Can you please help?
Depth-first search is implemented using a LIFO data structure, so you 'd need to swap the Queue for a Stack. Using a FIFO structure like a queue gives you BFS instead.
you can do it recursively
public IEnumerable<IContent> BuildContentFrom(IEnumerable<Node> nodes) {
foreach(var node in nodes){
yield node;
foreach(var c in BuildContentFrom(node.children)){
yield c;
}
}
}
This might become a problem with n-trees when n is large and/or the tree deep.
in which case you could use an accumulator
public IEnumerable<IContent> BuildContentFrom(IEnumerable<Node> nodes) {
if(!nodes.Any()) return Enumerable.Empty<IContent>();
var acc = new List<IContent>();
BuildContentFrom(nodes);
}
public IEnumerable<IContent> BuildContentFrom(IEnumerable<Node> nodes,
IList<IContent> acc) {
foreach(var node in nodes){
acc.Add(BuildContentFromSingle(node));
if(node.children.Any()) BuildContentFrom(node.children, acc);
}
}
Which is now tail recursive and if the compiler optimizes for that (a setting for C# as far as I remember) you will have no stack issues even with large trees.
Alternatively you can use a stack to collect the work you still need to perform
public IEnumerable<IContent> BuildContentFrom(IEnumerable<Node> nodes)
{
var stack= new Stack<Node>(nodes);
while (stack.Any())
{
var next = stack.Pop();
yield return BuildContentFromSingle(next);
foreach (var child in next.Children)
{
stack.push(child);
}
}
}
As an alternative, you could consider flattening the structure using recursion. Here's an example with a binary tree. It demonstrates a depth-first flattening traversal.
using System;
using System.Collections.Generic;
namespace Demo
{
public static class Program
{
static void Main(string[] args)
{
var tree = buildTree(5, true);
printTree1(tree);
Console.WriteLine("---------------------------------------------");
printTree2(tree);
}
// Print tree using direct recursion.
static void printTree1<T>(Node<T> tree)
{
if (tree != null)
{
Console.WriteLine(tree.Value);
printTree1(tree.Left);
printTree1(tree.Right);
}
}
// Print tree using flattened tree.
static void printTree2<T>(Node<T> tree)
{
foreach (var value in flatten(tree))
{
Console.WriteLine(value);
}
}
// Flatten tree using recursion.
static IEnumerable<T> flatten<T>(Node<T> root)
{
if (root == null)
{
yield break;
}
foreach (var node in flatten(root.Left))
{
yield return node;
}
foreach (var node in flatten(root.Right))
{
yield return node;
}
yield return root.Value;
}
static Node<string> buildTree(int depth, bool left)
{
if (depth > 0)
{
--depth;
return new Node<string>(buildTree(depth, true), buildTree(depth, false), "Node." + depth + (left ? ".L" : ".R"));
}
else
{
return new Node<string>(null, null, "Leaf." + (left ? "L" : "R"));
}
}
}
public sealed class Node<T>
{
public Node(Node<T> left, Node<T> right, T value)
{
_left = left;
_right = right;
_value = value;
}
public Node<T> Left { get { return _left; } }
public Node<T> Right { get { return _right; } }
public T Value { get { return _value; } }
private readonly Node<T> _left;
private readonly Node<T> _right;
private readonly T _value;
}
}
For your specific example, I think (without testing it) that you can do this:
public static IEnumerable<Node> Flatten(Node root)
{
foreach (var node in root.Children)
{
foreach (var child in Flatten(node))
{
yield return child;
}
}
yield return root;
}
Depending on whether you allow null nodes, you might need to add some null checking:
public static IEnumerable<Node> Flatten(Node root)
{
if (root != null)
{
foreach (var node in root.Children)
{
foreach (var child in Flatten(node))
{
if (child != null)
{
yield return child;
}
}
}
yield return root;
}
}

Dynamic derive Generic Type Parameter

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 + "'.");
}

Categories

Resources