有人可以告诉我如何实现递归的lambda表达式来遍历C#中的树结构。
答案 0 :(得分:70)
好的,我终于找到了一些空闲时间 我们走了:
class TreeNode
{
public string Value { get; set;}
public List<TreeNode> Nodes { get; set;}
public TreeNode()
{
Nodes = new List<TreeNode>();
}
}
Action<TreeNode> traverse = null;
traverse = (n) => { Console.WriteLine(n.Value); n.Nodes.ForEach(traverse);};
var root = new TreeNode { Value = "Root" };
root.Nodes.Add(new TreeNode { Value = "ChildA"} );
root.Nodes[0].Nodes.Add(new TreeNode { Value = "ChildA1" });
root.Nodes[0].Nodes.Add(new TreeNode { Value = "ChildA2" });
root.Nodes.Add(new TreeNode { Value = "ChildB"} );
root.Nodes[1].Nodes.Add(new TreeNode { Value = "ChildB1" });
root.Nodes[1].Nodes.Add(new TreeNode { Value = "ChildB2" });
traverse(root);
答案 1 :(得分:27)
正确的解决方案,实际上是许多函数式编程语言中的惯用解决方案,都是使用fixed-point combinator。简而言之:定点组合器回答了“我如何定义匿名函数是递归的?”的问题。但是解决方案非常重要,所以写完整篇文章来解释它们。
一个简单实用的选择是在定义之前“回到C:声明的滑稽动作”。尝试以下(“阶乘”功能):
Func<int, int> fact = null;
fact = x => (x == 0) ? 1 : x * fact(x - 1);
像魅力一样。
或者,对于类TreeNode
的对象上的预订树遍历,该对象适当地实现IEnumerable<TreeNode>
以覆盖其子项:
Action<TreeNode, Action<TreeNode>> preorderTraverse = null;
preorderTraverse = (node, action) => {
action(node);
foreach (var child in node) preorderTraverse(child, action);
};
答案 2 :(得分:15)
一个简单的选择是“回到过去”C和C ++的滑稽动作:定义之前的声明。请尝试以下方法:
Func<int, int> fact = null; fact = x => (x == 0) ? 1 : x * fact(x - 1);
像魅力一样。
是的,这确实有效,但有一点需要注意。 C#有可变引用。所以请确保你不小心做了这样的事情:
Func<int, int> fact = null;
fact = x => (x == 0) ? 1 : x * fact(x - 1);
// Make a new reference to the factorial function
Func<int, int> myFact = fact;
// Use the new reference to calculate the factorial of 4
myFact(4); // returns 24
// Modify the old reference
fact = x => x;
// Again, use the new reference to calculate
myFact(4); // returns 12
当然,这个例子有点人为,但是在使用可变引用时可能会发生这种情况。如果您使用aku链接中的组合器,则无法进行此操作。
答案 3 :(得分:2)
假设一个神话对象TreeItem,它包含一个Children集合来表示你的层次结构。
public void HandleTreeItems(Action<TreeItem> item, TreeItem parent)
{
if (parent.Children.Count > 0)
{
foreach (TreeItem ti in parent.Children)
{
HandleTreeItems(item, ti);
}
}
item(parent);
}
现在调用它,传入处理一个项目的lambda,方法是将其名称打印到控制台。
HandleTreeItems(item => { Console.WriteLine(item.Name); }, TreeItemRoot);