在 C# 中遍历树的递归 lambda 表达式

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/61143/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 10:19:52  来源:igfitidea点击:

Recursive lambda expression to traverse a tree in C#

提问by Joel Cunningham

Can someone show me how to implement a recursive lambda expression to traverse a tree structure in C#.

有人可以向我展示如何在 C# 中实现递归 lambda 表达式来遍历树结构。

采纳答案by aku

Ok, I found some free time finally.
Here we go:

好吧,我终于找到了一些空闲时间。
开始了:

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);

回答by DevelopingChris

Assuming a mythical object TreeItem, that conatins a Children collection to represent your hierarchy.

假设一个神话对象 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);
    }

Now to call it, passing in the lambda that handles one item, by printing its name to the console.

现在调用它,通过将其名称打印到控制台来传入处理一项的 lambda。

HandleTreeItems(item => { Console.WriteLine(item.Name); }, TreeItemRoot);

回答by Konrad Rudolph

A proper solution, and indeed the idiomatic solution in many functional programming languages, would be the use of a fixed-point combinator. In a nutshell: a fixed-point combinator answers the question “how do I define an anonymous function to be recursive?”. But the solution is so nontrivial that whole articles are written to explain them.

一个合适的解决方案,实际上是许多函数式编程语言中的惯用解决方案,是使用定点组合器。简而言之:定点组合器回答了“我如何定义一个匿名函数为递归?”的问题。但是解决方案非常重要,以至于写了整篇文章来解释它们。

A simple, pragmatic alternative is to “go back in time” to the antics of C: declaration before definition. Try the following (the “factorial” function):

一个简单实用的替代方法是“回到过去”,回到 C 的滑稽动作:定义之前的声明。尝试以下(“阶乘”函数):

Func<int, int> fact = null;
fact = x => (x == 0) ? 1 : x * fact(x - 1);

Works like a charm.

奇迹般有效。

Or, for a pre-order tree traversal on an object of class TreeNodewhich implements IEnumerable<TreeNode>appropriately to go over its children:

或者,对于类对象上的预排序树遍历,该对象适当地TreeNode实现遍历IEnumerable<TreeNode>其子项:

Action<TreeNode, Action<TreeNode>> preorderTraverse = null;
preorderTraverse = (node, action) => {
    action(node);
    foreach (var child in node) preorderTraverse(child, action);
};

回答by Tom Lokhorst

A simple alternative is to “go back in time” to the antics of C and C++: declaration before definition. Try the following:

Func<int, int> fact = null;
fact = x => (x == 0) ? 1 : x * fact(x - 1);

Works like a charm.

一个简单的替代方法是“回到过去”到 C 和 C++ 的滑稽动作:定义之前的声明。请尝试以下操作:

Func<int, int> fact = null;
fact = x => (x == 0) ? 1 : x * fact(x - 1);

奇迹般有效。

Yes, that does work, with one little caveat. C# has mutable references. So make sure you don't accidentally do something like this:

是的,这确实有效,但有一点需要注意。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

Of course, this example is a bit contrived, but this could happen when using mutable references. If you use the combinators from aku's links, this won't be possible.

当然,这个例子有点做作,但在使用可变引用时可能会发生这种情况。如果您使用aku链接中的组合器,这是不可能的。