我的TreeNode
课如下:
public class TreeNode
{
public enum NodeType { Root,Element, Category}
public TreeNode()
{
Children = new List<TreeNode>();
}
public List<TreeNode> Children { get; set; }
public string Name { get; set; }
public NodeType Type { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我有一个BuildTree
填充树结构的方法,为每个节点设置节点名称和类型(例如,第一个节点将设置为“根类型”,子节点可以是“元素”或“类别”类型)。
我正在寻找一种有效的方法(也许使用LINQ)修剪末端节点类型不是Category的树枝。关于如何实现这一目标的任何想法?
这里是一个可视示例:
之前:
Root
|
|_ NodeA (Element)
|_ Node B (Element)
| |_ Node B.1 (Category)
|_ Node C (Element)
| |_ Node C.1 (Element)
| |_Node C.1.1 (Category)
|_ Node D (Element)
|_Node D.1 (Element)
Run Code Online (Sandbox Code Playgroud)
之后:
Root
|
|_ Node B (Element)
| |_ Node B.1 (Category)
|_ Node C (Element)
|_ Node C.1 (Element)
|_Node C.1.1 (Category)
Run Code Online (Sandbox Code Playgroud)
提前致谢!
首先我们需要描述如何对树进行深度优先聚合:
//seed: leafNode -> accumulate
//func: interiorNode, children accumulates -> accumulate
public static TAccumulate Aggregate<TAccumulate>(
this TreeNode root,
Func<TreeNode, TAccumulate> seed,
Func<TreeNode, List<TAccumulate>, TAccumulate> func)
{
if (root.Children == null || !root.Children.Any())
return seed(root);
return func(root, children.Select(child => child.Aggregate(seed, func)).ToList());
}
Run Code Online (Sandbox Code Playgroud)
然后我们可以使用它进行修改,例如您请求的修改:
tree.Aggregate(
leaf => new
{
Keep = leaf.NodeType == TreeNode.NodeType.Category,
Node = leaf
},
(node, children) =>
{
var removal = new HashSet<TreeNode>(
children.Where(child => !child.Keep).Select(child => child.Node));
node.Children.RemoveAll(removal.Contains);
return new
{
Keep = children.Any(child => child.Keep),
Node = node
};
});
Run Code Online (Sandbox Code Playgroud)
这为您提供了一种简洁的声明性方式来描述您想要应用于树的变换,而无需在变换的描述中深入了解遍历的细节。