Reputation: 187
Given a class;
public class TreeNode
{
public string nodeType;
public string nodeName;
public List<TreeNode> Children;
}
instantiated by ;
var tree = new TreeNode()
{
nodeName = "Fred",
Children = new List<TreeNode>()
{
new TreeNode() { nodeName = "James" },
new TreeNode()
{
nodeName = "Lucy",
Children = new List<TreeNode>()
{
new TreeNode() { nodeName = "James",
Children = new List<TreeNode>()
{
new TreeNode() { nodeName = "Bob" },
new TreeNode() { nodeName = "Kevin" },
} },
new TreeNode() { nodeName = "Kevin" }
}
}
}
};
How would I go about filtering the list by "James" and return the tree as a collection like ;
Fred - James
Fred - Lucy - James
The smarts is that it does not need to include any child node of the filter criteria. I would like to use linq if possible but not sure if its possible.
Thanks
Upvotes: 0
Views: 88
Reputation: 117175
Here you go:
IEnumerable<TreeNode[]> Flatten(TreeNode node) =>
(node.Children ?? new List<TreeNode>())
.SelectMany(child => Flatten(child))
.Select(nodes => nodes.StartWith(node).ToArray())
.StartWith(new[] { node });
IEnumerable<TreeNode[]> results =
Flatten(tree)
.Where(nodes => nodes.Last().nodeName == "James");
string text =
String.Join(
Environment.NewLine,
results.Select(nodes =>
String.Join(
" - ",
nodes.Select(node => node.nodeName))));
That gives me:
Fred - James Fred - Lucy - James
Here's a version that doesn't require Microsoft's System.Interactive
NuGet package:
IEnumerable<TreeNode[]> Flatten(TreeNode node) =>
new[] { new[] { node } }
.Concat(
(node.Children ?? new List<TreeNode>())
.SelectMany(child => Flatten(child))
.Select(nodes => new[] { node }.Concat(nodes).ToArray()));
Upvotes: 1