Рекурсивное лямбда-выражение для обхода дерева в C#
может кто-нибудь показать мне, как реализовать рекурсивное лямбда-выражение для обхода древовидной структуры в C#.
4 ответа:
Ок, я нашел немного свободного времени, наконец.
Здесь мы идем: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);
правильное решение, и действительно идиоматическое решение во многих функциональных языках программирования, было бы использование комбинатор с фиксированной точкой. В двух словах: комбинатор с фиксированной точкой отвечает на вопрос "Как определить анонимную функцию как рекурсивную?". Но решение настолько нетривиально, что для их объяснения пишутся целые статьи.
простая, прагматическая альтернатива - "вернуться назад во времени" к выходкам c: объявление перед определением. Пытаться следующее:
Func<int, int> fact = null; fact = x => (x == 0) ? 1 : x * fact(x - 1);
работает как шарм.
простой альтернативой является "вернуться назад во времени" к выходкам 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
конечно, этот пример немного надуманный, но это может произойти при использовании изменяемых ссылок. Если вы используете комбинаторы от Акуссылки, это не будет возможно.
если предположить, что мифические treeitem, в объект, который будет показан набор детей для представления иерархии.
public void HandleTreeItems(Action<TreeItem> item, TreeItem parent) { if (parent.Children.Count > 0) { foreach (TreeItem ti in parent.Children) { HandleTreeItems(item, ti); } } item(parent); }
теперь, чтобы вызвать его, передавая лямбду, которая обрабатывает один элемент, печатая его имя на консоль.
HandleTreeItems(item => { Console.WriteLine(item.Name); }, TreeItemRoot);