I have a tree created from this class.
class Node
{
public string Key { get; }
public List<Node> Children { get; }
}
I want to search in all children and all their children to get the ones matching a condition:
node.Key == SomeSpecialKey
How can I implement it?
It's a misconception that this requires recursion. It will require a stack or a queue and the easiest way is to implement it using recursion. For sake of completeness I'll provide a non-recursive answer.
static IEnumerable<Node> Descendants(this Node root)
{
var nodes = new Stack<Node>(new[] {root});
while (nodes.Any())
{
Node node = nodes.Pop();
yield return node;
foreach (var n in node.Children) nodes.Push(n);
}
}
Use this expression for example to use it:
root.Descendants().Where(node => node.Key == SomeSpecialKey)
If you want to maintain Linq like syntax, you can use a method to obtain all the descendants (children + children's children etc.)
static class NodeExtensions
{
public static IEnumerable<Node> Descendants(this Node node)
{
return node.Children.Concat(node.Children.SelectMany(n => n.Descendants()));
}
}
This enumerable can then be queried like any other using where or first or whatever.
Searching a Tree of Objects with Linq
public static class TreeToEnumerableEx
{
public static IEnumerable<T> AsDepthFirstEnumerable<T>(this T head, Func<T, IEnumerable<T>> childrenFunc)
{
yield return head;
foreach (var node in childrenFunc(head))
{
foreach (var child in AsDepthFirstEnumerable(node, childrenFunc))
{
yield return child;
}
}
}
public static IEnumerable<T> AsBreadthFirstEnumerable<T>(this T head, Func<T, IEnumerable<T>> childrenFunc)
{
yield return head;
var last = head;
foreach (var node in AsBreadthFirstEnumerable(head, childrenFunc))
{
foreach (var child in childrenFunc(node))
{
yield return child;
last = child;
}
if (last.Equals(node)) yield break;
}
}
}
You can try this extension method to enumerate the tree nodes:
static IEnumerable<Node> GetTreeNodes(this Node rootNode)
{
yield return rootNode;
foreach (var childNode in rootNode.Children)
{
foreach (var child in childNode.GetTreeNodes())
yield return child;
}
}
Then use that with a Where() clause:
var matchingNodes = rootNode.GetTreeNodes().Where(x => x.Key == SomeSpecialKey);
Why not use an IEnumerable<T> extension method
public static IEnumerable<TResult> SelectHierarchy<TResult>(this IEnumerable<TResult> source, Func<TResult, IEnumerable<TResult>> collectionSelector, Func<TResult, bool> predicate)
{
if (source == null)
{
yield break;
}
foreach (var item in source)
{
if (predicate(item))
{
yield return item;
}
var childResults = SelectHierarchy(collectionSelector(item), collectionSelector, predicate);
foreach (var childItem in childResults)
{
yield return childItem;
}
}
}
then just do this
var result = nodes.Children.SelectHierarchy(n => n.Children, n => n.Key.IndexOf(searchString) != -1);
Perhaps you need just
node.Children.Where(child => child.Key == SomeSpecialKey)
Or, if you need to search one level deeper,
node.Children.SelectMany(
child => child.Children.Where(child => child.Key == SomeSpecialKey))
If you need to search on all levels, take the following:
IEnumerable<Node> FlattenAndFilter(Node source)
{
List<Node> l = new List();
if (source.Key == SomeSpecialKey)
l.Add(source);
return
l.Concat(source.Children.SelectMany(child => FlattenAndFilter(child)));
}
public class Node
{
string key;
List<Node> children;
public Node(string key)
{
this.key = key;
children = new List<Node>();
}
public string Key { get { return key; } }
public List<Node> Children { get { return children; } }
public Node Find(Func<Node, bool> myFunc)
{
foreach (Node node in Children)
{
if (myFunc(node))
{
return node;
}
else
{
Node test = node.Find(myFunc);
if (test != null)
return test;
}
}
return null;
}
}
And then you can search like:
Node root = new Node("root");
Node child1 = new Node("child1");
Node child2 = new Node("child2");
Node child3 = new Node("child3");
Node child4 = new Node("child4");
Node child5 = new Node("child5");
Node child6 = new Node("child6");
root.Children.Add(child1);
root.Children.Add(child2);
child1.Children.Add(child3);
child2.Children.Add(child4);
child4.Children.Add(child5);
child5.Children.Add(child6);
Node test = root.Find(p => p.Key == "child6");
And just for fun (almost a decade later) an answer also using Generics but with a Stack and While loop, based off the accepted answer by #vidstige.
public static class TypeExtentions
{
public static IEnumerable<T> Descendants<T>(this T root, Func<T, IEnumerable<T>> selector)
{
var nodes = new Stack<T>(new[] { root });
while (nodes.Any())
{
T node = nodes.Pop();
yield return node;
foreach (var n in selector(node)) nodes.Push(n);
}
}
public static IEnumerable<T> Descendants<T>(this IEnumerable<T> encounter, Func<T, IEnumerable<T>> selector)
{
var nodes = new Stack<T>(encounter);
while (nodes.Any())
{
T node = nodes.Pop();
yield return node;
if (selector(node) != null)
foreach (var n in selector(node))
nodes.Push(n);
}
}
}
Given a collection one can use like this
var myNode = ListNodes.Descendants(x => x.Children).Where(x => x.Key == SomeKey);
or with a root object
var myNode = root.Descendants(x => x.Children).Where(x => x.Key == SomeKey);
A while back I wrote a codeproject article which describes how to use Linq to query tree-like structures:
http://www.codeproject.com/KB/linq/LinqToTree.aspx
This provides a linq-to-XML style API where you can search descendants, children, ancestors etc...
Probably overkill for your current problem, but might be of interest to others.
You can use this extension method to query the tree.
public static IEnumerable<Node> InTree(this Node treeNode)
{
yield return treeNode;
foreach (var childNode in treeNode.Children)
foreach (var flattendChild in InTree(childNode))
yield return flattendChild;
}
I have a generic extension method that can flatten any IEnumerable<T> and from that flattened collection, you can get the node you want.
public static IEnumerable<T> FlattenHierarchy<T>(this T node, Func<T, IEnumerable<T>> getChildEnumerator)
{
yield return node;
if (getChildEnumerator(node) != null)
{
foreach (var child in getChildEnumerator(node))
{
foreach (var childOrDescendant in child.FlattenHierarchy(getChildEnumerator))
{
yield return childOrDescendant;
}
}
}
}
Use this like this:
var q = from node in myTree.FlattenHierarchy(x => x.Children)
where node.Key == "MyKey"
select node;
var theNode = q.SingleOrDefault();
I use the following implementations for enumerating Tree items
public static IEnumerable<Node> DepthFirstUnfold(this Node root) =>
ObjectAsEnumerable(root).Concat(root.Children.SelectMany(DepthFirstUnfold));
public static IEnumerable<Node> BreadthFirstUnfold(this Node root) {
var queue = new Queue<IEnumerable<Node>>();
queue.Enqueue(ObjectAsEnumerable(root));
while (queue.Count != 0)
foreach (var node in queue.Dequeue()) {
yield return node;
queue.Enqueue(node.Children);
}
}
private static IEnumerable<T> ObjectAsEnumerable<T>(T obj) {
yield return obj;
}
BreadthFirstUnfold in implementation above uses queue of node sequences instead of nodes queue. This is not classic BFS algorithm way.
Related
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.
So I've been scavenging the forums for a solution to this problem and I have this method for finding a node in a graph given a predicate:
public static class Extensions
{
public static IEnumerable<T> FindWhere<T>(this T root, Func<T, bool> predicate,
Func<T, IEnumerable<T>> getChildren)
where T : class
{
var stack = new Stack<T>();
stack.Push(root);
while (stack.Count != 0)
{
T item = stack.Pop();
if (item != null)
{
yield return item;
}
foreach (var child in getChildren(item))
stack.Push(child);
}
}
}
This should work most of the way, but how do I get the predicate into the method so that I can find any node in the graph that I wish to find? Any hints appreciated.
You can use a lambda expression like this:
myClass.FindWhere(x => x.HasSomeProperty, y => y.GetChildren())
Or you can declare methods with the right signature and pass those in.
bool IsOkay(MyClass mc) { ... }
IEnumerable<MyClass> GetChildren(MyClass mc) { ... }
...
myClass.FindWhere(IsOkay, GetChildren)
in an mvc application I've got a menu composed of the following structure
public class MenuItem
{
public string Action {get;set;}
public string Controller {get;set;}
public string Text {get;set;}
public List<MenuItem> Children {get;set;}
}
Consider a simple compisition of
Root
\-Item1
\-Item2
\-Item2_1
\-Item2_2
\-Item_2_2_1
\-Item_2_2_2
\-Item3
I want to get the item Item_2_2_2 (consider it has Action="Index", Controller="ABC")
How can I write a function (or better extension method of T) that iterates trought the collection and get the item it matches that condition ?
Thanks
You can write an extension method to "flatten" hierarchies...
public static IEnumerable<T> Flatten<T>(this T value, Func<T, IEnumerable<T>> inner) {
foreach (var i in inner(value)) {
foreach (var j in Flatten(i, inner)) {
yield return j;
}
}
yield return value;
}
...then use ordinary LINQ:
items.Flatten(i => i.Children).Where(i => ...
Since the question is about "get the items matches on a condition", it's possible to directly include the search criteria into the recursion, and by this way, optimize the graph traversal by yielding only once over the collection :
Moreover, since you can use a .Take(10) operator over the result, and since there are different ways of walking over a graph, I included a depth-first / breadth-first option.
Moreover bis, since we are on Stackoverflow, and even if the default max stack size on .Net is of 1MB, it's improbable but not impossible to throw a StackOverflowException. So here's also a safe, non-recursive version of the depth-first graph traversal.
public static IEnumerable<T> Search<T>(this T node, Func<T, IEnumerable<T>> childs, Func<T, bool> condition, GraphTraversal mode = GraphTraversal.DepthFirst)
{
if (node == null || childs == null || condition == null)
throw new ArgumentNullException();
if (mode == GraphTraversal.DepthFirst)
return node.depthFirstTraversal(childs, condition);
else if (mode == GraphTraversal.DepthFirstNoStackOverflow)
return node.depthFirstTraversalWithoutStackoverflow(childs, condition);
else
return node.breadthFirstTraversal(childs, condition);
}
private static IEnumerable<T> depthFirstTraversal<T>(this T node, Func<T, IEnumerable<T>> childs, Func<T, bool> condition)
{
IEnumerable<T> childrens = childs(node);
if (childrens == null)
yield break;
if (condition(node))
yield return node;
foreach (T i in childrens)
{
foreach (T j in depthFirstTraversal(i, childs, condition))
{
if (condition(j))
yield return j;
}
}
}
private static IEnumerable<T> breadthFirstTraversal<T>(this T node, Func<T, IEnumerable<T>> childs, Func<T, bool> condition)
{
Queue<T> queue = new Queue<T>();
queue.Enqueue(node);
while (queue.Count > 0)
{
T currentnode = queue.Dequeue();
if (condition(currentnode))
yield return currentnode;
IEnumerable<T> childrens = childs(currentnode);
if (childrens != null)
{
foreach (T child in childrens)
queue.Enqueue(child);
}
}
}
private static IEnumerable<T> depthFirstTraversalWithoutStackoverflow<T>(this T node, Func<T, IEnumerable<T>> childs, Func<T, bool> condition)
{
Stack<T> stack = new Stack<T>();
stack.Push(node);
while (stack.Count > 0)
{
T currentnode = stack.Pop();
if (condition(currentnode))
yield return currentnode;
var childrens = childs(currentnode);
if (childrens != null)
{
foreach (var child in childrens)
stack.Push(child);
}
}
}
public enum GraphTraversal { DepthFirst, DepthFirstNoStackOverflow, BreadthFirst }
You use it like this :
var found = rootItem.Search(i => i.Children, i => i.Action == "Index" && i.Controller == "ABC");
Alex's solution is good, but when doing
items.Flatten(i => i.Children).Where(i => ...
the collection is fully yielded one time with Flatten, and one other time with Where, and lacks some null checks.
As Alex pointed it, the iteration is deferred, but since each IEnumerable<T> operator (and each foreach) need to call enumerator.GetNext(), so there will be performance improvement by integrating the predicate directly into the recursion loop.
This question already has answers here:
How to search Hierarchical Data with Linq
(8 answers)
Closed 9 years ago.
Imagine an object with the properties:
class TestObject
{
public string Name { get; set; }
public Collection<TestObject> Children { get; set; }
}
Now initialize some in a jagged fashion:
var person1 = new TestObject(){
Name = "Joe",
Children = new Collection<TestObject>(){ childCollection1 };
};
var person2 = new TestObject(){
Name = "Mary",
Children = new Collection<TestObject>(){ childCollection2 };
};
Where Joe's childCollection is only one level deep, but Mary's children have children, who also have children.
I have attempted to use SelectMany with no luck.
// Works
var joe = person1.Children.SelectMany(c => c.Children).Concat(person1.Children);
// Does not work - only returns 1 level deep
var mary = person2.Children.SelectMany(c => c.Children).Concat(person2.Children);
What is the best way to retrieve a result containing every child, to an unknown depth?
You can write a generic traverse method like this:
public static IEnumerable<T> Traverse<T>(T root,
Func<T, IEnumerable<T>> childSelector)
{
var stack = new Stack<T>();
stack.Push(root);
while (stack.Any())
{
var next = stack.Pop();
yield return next;
foreach (var child in childSelector(next))
stack.Push(child);
}
}
This is a general model that's useful for traversing trees in general. Note that this will do a depth first search. If you want a breath first search you would use a Queue<T> instead of a Stack<T>.
Helper method
public static IEnumerable<T> Traversal<T>(
T root,
Func<T, IEnumerable<T>> getChildren)
{
if (root == null)
{
yield break;
}
yield return root;
var children = getChildren(root);
if (children == null)
{
yield break;
}
foreach (var child in children)
{
foreach (var node in Traversal(child, getChildren))
{
yield return node;
}
}
}
//Or if you don't need all those null checks, here's a more compact version.
public static IEnumerable<T> Traversal<T>(
T root,
Func<T, IEnumerable<T>> getChildren)
{
yield return root;
foreach (var child in getChildren(root))
foreach (var node in Traversal(child, getChildren))
yield return node;
}
//If you like a LINQ/functional style better, this is also equivalent.
public static IEnumerable<T> Traversal<T>(
T root,
Func<T, IEnumerable<T>> getChildren)
{
return new T[] { root }
.Concat(getChildren(root)
.SelectMany(child => Traversal(child, getChildren)));
}
Usage
var everybody = Traversal(person, x => x.Children);
Comments
You can easily modify the Traversal method to behave exactly the way you want. For example, if you only want leaf nodes, then you should only yield return root; when children is null or empty.
Performance concerns
If performance is any kind of issue, consider the LINQ/functional implementation above or take a look at Servy's answer, either of which should be more efficient than the version using yield ....
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;
}
}