Query a TreeNodeCollection - c#

I have a treeview control on a windows form UI and it has a few nodes (with multiple child nodes).
I want to query the nodes collection so as to, say,
1. select those whose name start with 'x'
2. select those which do not have any data in Node.Tag field.
Can someone please suggest me a way to do this. Linq would make it easy and neat, but I found nothing much on Linq to query TreeNodeCollection.
Thanks,

Because TreeNodeCollection pre-dates .NET 2.0, it isn't a generic collection, so it doesn't implement IEnumerable<T>, which is the 'master' type for LINQ goodness.
However, you can just call .Cast<TreeNode>() on a TreeNodeCollection, and you get an IEnumerable<TreeNode>, which you can then do all the LINQy goodness to.
(this approach works for any such collection that implements IEnumerable but not IEnumerable<T>)

You may try something like this with a Fixpoint operator allowing recursive lambdas
// Fix point operator
public static Func<T, T> Fix<T>(Func<Func<T, T>, Func<T, T>> f)
{
return t => f(Fix<T>(f))(t);
}
then
// your treeView
var tv = new TreeView();
// Your filter Func
Func<TreeNode, bool> filterStartWithXorNoData =
node => node.Text.StartsWith("x") || string.IsNullOrEmpty(node.Text);
// Your recursive lambda
var filteredNodes = Fix<IEnumerable<TreeNode>>(
f =>
nodeList =>
nodeList.SelectMany(node => f(node.ChildNodes.Cast<TreeNode>()))
.Union(nodeList.Where(filterStartWithXorNoData)))
(tv.Nodes.Cast<TreeNode>());

I've tried something similar recently and struggled with the LINQ approach due to the nested nodes collection under each parent.
I solved my problem with a recursive function that searched all nodes. Reasonably elegant.
VB:
Private Function FindNode(name As String, root As TreeNode) As TreeNode
For Each n As TreeNode In root.Nodes
If n.Name = name Then
'Found, get out
Return n
Else
'Recursively call FindNode to search this node's children
Dim soughtNode = FindNode(name, n)
If soughtNode IsNot Nothing Then
Return soughtNode
End If
End If
Next
Return Nothing
End Function

Related

Is there a simpler way that to skip from node explored in tree? [C#]

I have a tree that can have the same node.
If it found the node explored, then I want to skip the node.
Of course, this is a simple topic but I am curious if there is a simpler way.
The code that comes to mind is something like this:
void Explore(Tree tree, HashSet<Tree> exploredTrees)
{
if (exploredTrees.Contains(tree))
continue;
foreach(var childTree in tree.ChildTree)
{
Explore(childTree);
exploredTrees.Add(childTree);
}
}
void static Program()
{
// it assumes there is data in the tree.
Tree tree = new Tree();
Explore(tree, new HashSet());
}
I've been using the code above so far but the second parameter getting on my nerves (new HashSet() for the above example).
As you know to achieve this purpose it must need a data structure to store the data explored.
However, I'm not satisfied because the data structure has to pass from the external. (ex: Explore(tree, new HashSet()))
Is there a way to achieve this purpose without the second parameter in C#?
I don't want to use static keyword because it has to remember to clear the data structure at external.
Thank you for reading.
The general approach is correct, but you could simply add a helper method that creates the hashSet for you: void Explore(Tree tree) => Explore(tree, new HashSet<Tree>())
Or you could use an iterative solution that lets you keep the HashSet as a local variable:
public static IEnumerable<T> DepthFirstLoopSafe<T>(T self, Func<T, IEnumerable<T>> selector, IEqualityComparer<T> equalityComparer = default)
{
var stack = new Stack<T>();
var visited = new HashSet<T>(equalityComparer ?? EqualityComparer<T>.Default);
stack.Push(self);
while (stack.Count > 0)
{
var current = stack.Pop();
visited.Add(current);
yield return current;
foreach (var child in selector(current))
{
if (!visited.Contains(child))
{
stack.Push(child);
}
}
}
}
Called like DepthFirstLoopSafe(tree, t => t.ChildTree). I like to use generics to describe the iteration of trees, since it allows reuse of code for all kinds of trees, regardless of type or how the tree is described.

Recursive collection search

I have a collection (List<Element>) of objects as described below:
class Element
{
string Name;
string Value;
ICollection<Element> ChildCollection;
IDictionary<string, string> Attributes;
}
I build a List<Element> collection of Element objects based on some XML that I read in, this I am quite happy with. How to implement searching of these elements currently has me, not stumped, but wondering if there is a better solution.
The structure of the collection looks something like this:
- Element (A)
- Element (A1)
- Element (A1.1)
- Element (A2)
- Element (B)
- Element (B1)
- Element (B1.1)
- Element (B1.2)
- Element (C)
- Element (C1)
- Element (C2)
- Element (C3)
Currently I am using recursion to search the Attributes dictionary of each top level (A, B, C) Element for a particular KeyValuePair. If I do not find it in the top level Element I start searching its ChildElement collection (1, 1.1, 2, 2.1, n, etc.) in the same manner.
What I am curious about is if there is a better method of implementing a search on these objects or if recursion is the better answer in this instance, if I should implement the search as I am currently, top -> child -> child -> etc. or if I should search in some other manner such as all top levels first?
Could I, and would it be reasonable to use the TPL to search each top level (A, B, C) in parallel?
Recursion is one way of implementing a tree search where you visit elements in depth-first order. You can implement the same algorithm with a loop instead of recursion by using a stack data structure to store the nodes of your tree that you need to visit.
If you use the same algorithm with a queue instead of a stack, the search would proceed in breath-first order.
In both cases the general algorithm looks like this:
var nodes = ... // some collection of nodes
nodes.Add(root);
while (nodes.Count != 0) {
var current = nodes.Remove ... // Take the current node from the collection.
foreach (var child in current.ChildCollection) {
nodes.Add(child);
}
// Process the current node
if (current.Attributes ...) {
...
}
}
Note that the algorithm is not recursive: it uses an explicit collection of nodes to save the current state of the search, whereas a recursive implementation uses the call stack for the same purpose. If nodes is a Stack<Element>, the search proceeds in depth-first order; if nodes is a Queue<Element>, the search proceeds in breadth-first order.
I grabbed this bit from SO somewhere, Its not mine but I cant provide a link to it. This class Flattens out a treeview for a recursive search, looks like it should do the same for you.
public static class SOExtension
{
public static IEnumerable<TreeNode> FlattenTree(this TreeView tv)
{
return FlattenTree(tv.Nodes);
}
public static IEnumerable<TreeNode> FlattenTree(this TreeNodeCollection coll)
{
return coll.Cast<TreeNode>()
.Concat(coll.Cast<TreeNode>()
.SelectMany(x => FlattenTree(x.Nodes)));
}
}
I found the link I got this from - its very easy to use. have a look. Is there a method for searching for TreeNode.Text field in TreeView.Nodes collection?
You can re-use existing components designed specifically for traversing in different ways, such as NETFx IEnumerable.Traverse Extension Method. It allows you to depth or breadth first. It lets you traverse an enumerable tree, depth or breadth first.
Example to get a flattened enumerable of directories:
IEnumerable<DirectoryInfo> directories = ... ;
IEnumerable<DirectoryInfo> allDirsFlattened = directories.Traverse(TraverseKind.BreadthFirst, dir => dir.EnumerateDirectories());
foreach (DirectoryInfo directoryInfo in allDirsFlattened)
{
...
}
For BreadhFirst it uses Queue<T> internally and for DepthFirst it uses Stack<T> internally.
It is not traversing nodes parallell and unless the traversal is resource demanding it isn't appropriate to use parallellism at this level. But that depends on the context.

LINQ: Transforming items in a collection

Is there a LINQ method to modify items in a collection, such as simply setting a property of each item in a collection? Something like this:
var items = new []{ new Item { IsActive = true } }
var items = items.Transform(i => i.IsActive = false)
where Touch enumerates each item and applies the transformation. BTW, I am aware of the SELECT extension method, but this would require I expose a method on the type that does this transformation and return the same reference.
var items = items.Select(i => i.Transform())
where Item.Transform returns does the transformation and return the same instance.
TIA
No, there are no methods in standard LINQ that allows you to modify items in a collection. LINQ is for querying collections and not for causing side-effects (e.g., mutating the items). Eric Lippert goes into the idea in more detail in his blog post: “foreach” vs “ForEach”.
Just use a loop.
foreach (var item in items)
{
item.IsActive = false;
}
LINQ is for querying. Use a simple loop if you want to modify. Just use the right tool for the right job. LINQ is not a messiah for everything.
There's a ForEach() on List, so you can do items.ToList().ForEach(i => i.IsActive = false). You might want to read this though.
The documentation page on MSDN for the Enumerable class lists all LINQ methods, and unfortunately no method there does what you want. LINQ is a query language and is not intended to modify collections. It is functional in its nature, meaning that it doesn't modify the collection it operates on, rather it returns a new enumerable.
For your purposes it is better to simply use a foreach loop, or if you feel the need write your own extension method to do what you want, eg.
public static void ForEach<T>(this IEnumerable<T> seq, Action<T> action)
{
foreach (T item in seq)
action(item);
}
which could then be used as you wanted:
items.ForEach(i => i.IsActive = false)

Enumerating Collections that are not inherently IEnumerable?

When you want to recursively enumerate a hierarchical object, selecting some elements based on some criteria, there are numerous examples of techniques like "flattening" and then filtering using Linq : like those found here :
link text
But, when you are enumerating something like the Controls collection of a Form, or the Nodes collection of a TreeView, I have been unable to use these types of techniques because they seem to require an argument (to the extension method) which is an IEnumerable collection : passing in SomeForm.Controls does not compile.
The most useful thing I found was this :
link text
Which does give you an extension method for Control.ControlCollection with an IEnumerable result you can then use with Linq.
I've modified the above example to parse the Nodes of a TreeView with no problem.
public static IEnumerable<TreeNode> GetNodesRecursively(this TreeNodeCollection nodeCollection)
{
foreach (TreeNode theNode in nodeCollection)
{
yield return theNode;
if (theNode.Nodes.Count > 0)
{
foreach (TreeNode subNode in theNode.Nodes.GetNodesRecursively())
{
yield return subNode;
}
}
}
}
This is the kind of code I'm writing now using the extension method :
var theNodes = treeView1.Nodes.GetNodesRecursively();
var filteredNodes =
(
from n in theNodes
where n.Text.Contains("1")
select n
).ToList();
And I think there may be a more elegant way to do this where the constraint(s) are passed in.
What I want to know if it is possible to define such procedures generically, so that : at run-time I can pass in the type of collection, as well as the actual collection, to a generic parameter, so the code is independent of whether it's a TreeNodeCollection or Controls.Collection.
It would also interest me to know if there's any other way (cheaper ? fastser ?) than that shown in the second link (above) to get a TreeNodeCollection or Control.ControlCollection in a form usable by Linq.
A comment by Leppie about 'SelectMany in the SO post linked to first (above) seems like a clue.
My experiments with SelectMany have been : well, call them "disasters." :)
Appreciate any pointers. I have spent several hours reading every SO post I could find that touched on these areas, and rambling my way into such exotica as the "y-combinator." A "humbling" experience, I might add :)
This code should do the trick
public static class Extensions
{
public static IEnumerable<T> GetRecursively<T>(this IEnumerable collection,
Func<T, IEnumerable> selector)
{
foreach (var item in collection.OfType<T>())
{
yield return item;
IEnumerable<T> children = selector(item).GetRecursively(selector);
foreach (var child in children)
{
yield return child;
}
}
}
}
Here's an example of how to use it
TreeView view = new TreeView();
// ...
IEnumerable<TreeNode> nodes = view.Nodes.
.GetRecursively<TreeNode>(item => item.Nodes);
Update: In response to Eric Lippert's post.
Here's a much improved version using the technique discussed in All About Iterators.
public static class Extensions
{
public static IEnumerable<T> GetItems<T>(this IEnumerable collection,
Func<T, IEnumerable> selector)
{
Stack<IEnumerable<T>> stack = new Stack<IEnumerable<T>>();
stack.Push(collection.OfType<T>());
while (stack.Count > 0)
{
IEnumerable<T> items = stack.Pop();
foreach (var item in items)
{
yield return item;
IEnumerable<T> children = selector(item).OfType<T>();
stack.Push(children);
}
}
}
}
I did a simple performance test using the following benchmarking technique. The results speak for themselves. The depth of the tree has only marginal impact on the performance of the second solution; whereas the performance decreases rapidly for the first solution, eventually leadning to a StackOverflowException when the depth of the tree becomes too great.
You seem to be on the right track and the answers above have some good ideas. But I note that all these recursive solutions have some deep flaws.
Let's suppose the tree in question has a total of n nodes with a max tree depth of d <= n.
First off, they consume system stack space in the depth of the tree. If the tree structure is very deep, then this can blow the stack and crash the program. Tree depth d is O(lg n), depending on the branching factor of the tree. Worse case is no branching at all -- just a linked list -- in which case a tree with only a few hundred nodes will blow the stack.
Second, what you're doing here is building an iterator that calls an iterator that calls an iterator ... so that every MoveNext() on the top iterator actually does a chain of calls that is again O(d) in cost. If you do this on every node, then the total cost in calls is O(nd) which is worst case O(n^2) and best case O(n lg n). You can do better than both; there's no reason why this cannot be linear in time.
The trick is to stop using the small, fragile system stack to keep track of what to do next, and to start using a heap-allocated stack to explicitly keep track.
You should add to your reading list Wes Dyer's article on this:
https://blogs.msdn.microsoft.com/wesdyer/2007/03/23/all-about-iterators/
He gives some good techniques at the end for writing recursive iterators.
I'm not sure about TreeNodes, but you can make the Controls collection of a form IEnumerable by using System.Linq and, for example
var ts = (from t in this.Controls.OfType<TextBox>
where t.Name.Contains("fish")
select t);
//Will get all the textboxes whose Names contain "fish"
Sorry to say I don't know how to make this recursive, off the top of my head.
Based on mrydengren's solution:
public static IEnumerable<T> GetRecursively<T>(this IEnumerable collection,
Func<T, IEnumerable> selector,
Func<T, bool> predicate)
{
foreach (var item in collection.OfType<T>())
{
if(!predicate(item)) continue;
yield return item;
IEnumerable<T> children = selector(item).GetRecursively(selector, predicate);
foreach (var child in children)
{
yield return child;
}
}
}
var theNodes = treeView1.Nodes.GetRecursively<TreeNode>(
x => x.Nodes,
n => n.Text.Contains("1")).ToList();
Edit: for BillW
I guess you are asking for something like this.
public static IEnumerable<T> <T,TCollection> GetNodesRecursively(this TCollection nodeCollection, Func<T, TCollection> getSub)
where T, TCollection: IEnumerable
{
foreach (var theNode in )
{
yield return theNode;
foreach (var subNode in GetNodesRecursively(theNode, getSub))
{
yield return subNode;
}
}
}
var all_control = GetNodesRecursively(control, c=>c.Controls).ToList();

Handling common recursive functions

I've noticed that in my project, we frequently are writing recursive functions.
My question is: is there any way to create the recursive function as generic function for each hierarchy structure that is using the recursive iteration?
Maybe I can use a delegate that gets the root and the end flag of the recursion?
Any ideas?
Thanks.
My question is: is there any way to create the recursive function as generic function for each hierarchy structure that is using the recusive iteration?
may be i can use a delegate that gets the root and the end flag of the recursive?
Yes - The only thing you need is a delegate function that computes a list of children for each element. The function terminates when no children are returned.
delegate IEnumerable<TNode> ChildSelector<TNode>(TNode Root);
static IEnumerable<TNode> Traverse<TNode>(this TNode Root, ChildSelector<TNode> Children) {
// Visit current node (PreOrder)
yield return Root;
// Visit children
foreach (var Child in Children(Root))
foreach (var el in Traverse(Child, Children))
yield return el;
}
Example:
static void Main(string[] args) {
var Init = // Some path
var Data = Init.Traverse(Dir => Directory.GetDirectories(Dir, "*", SearchOption.TopDirectoryOnly));
foreach (var Dir in Data)
Console.WriteLine(Dir);
Console.ReadKey();
}
I think what you want is a way to work with hierarchical structures in a generic way ("generic" as defined in English, not necessarily as defined in .Net). For example, this is something I wrote once when I needed to get all the Controls inside a Windows Form:
public static IEnumerable<T> SelectManyRecursive<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector)
{
if (items == null)
throw new ArgumentNullException("items");
if (selector == null)
throw new ArgumentNullException("selector");
return SelectManyRecursiveInternal(items, selector);
}
private static IEnumerable<T> SelectManyRecursiveInternal<T>(this IEnumerable<T> items, Func<T, IEnumerable<T>> selector)
{
foreach (T item in items)
{
yield return item;
IEnumerable<T> subitems = selector(item);
if (subitems != null)
{
foreach (T subitem in subitems.SelectManyRecursive(selector))
yield return subitem;
}
}
}
// sample use, get Text from some TextBoxes in the form
var strings = form.Controls
.SelectManyRecursive(c => c.Controls) // all controls
.OfType<TextBox>() // filter by type
.Where(c => c.Text.StartWith("P")) // filter by text
.Select(c => c.Text);
Another example: a Category class where each Category could have ChildCategories (same way a Control has a Controls collection) and assuming that rootCategory is directly or indirectly the parent of all categories:
// get all categories that are enabled
var categories = from c in rootCategory.SelectManyRecursive(c => c.ChildCategories)
where c.Enabled
select c;
I'm not sure what exactly your question is asking for but a recursive function can be generic. There's no limitation on that. For instance:
int CountLinkedListNodes<T>(MyLinkedList<T> input) {
if (input == null) return 0;
return 1 + CountLinkedListNodes<T>(input.Next);
}
An easier and also generic approach might be to cache the results of the function and use the "real" function only when the result is known - the effectivness of this approach depends how frequently the same set of parameters is used during your recursion.
If you know Perl you should check the first 4 chapters of Higher-Order Perl which are available as a EBook, the ideas presented are language-independent.
It sounds like your solution can successfully use the Visitor Pattern.
You can create a specific variation of the Visitor Pattern by creating a hierarchical visitor pattern.
It is a little complex to discuss entirely here, but that should get you started into some research. The basic idea is that you have a class that knows how to traverse the structure, and then you have Visitor classes that know how to process a particular node. You can separate the traversal of the tree with the processing of nodes.

Categories

Resources