Expresión lambda recursiva para atravesar un árbol en C#


Puede alguien mostrarme cómo implementar una expresión lambda recursiva para atravesar una estructura de árbol en C#.

Author: aku, 2008-09-14

4 answers

Ok, finalmente encontré algo de tiempo libre.
Aquí vamos:

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);
 68
Author: aku,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-14 10:44:56

Una solución adecuada, y de hecho la solución idiomática en muchos lenguajes de programación funcionales, sería el uso de un combinador de punto fijo . En pocas palabras: un combinador de punto fijo responde a la pregunta " ¿cómo defino que una función anónima sea recursiva?". Pero la solución es tan no trivial que se escriben artículos enteros para explicarlos.

Una alternativa simple y pragmática es "retroceder en el tiempo" a las travesuras de C: declaración antes de definición. Prueba el siguiente:

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

Funciona como un encanto.

 23
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-20 18:03:17

Una alternativa simple es "retroceder en el tiempo" a las travesuras de C y C++: declaración antes de definición. Prueba lo siguiente:

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

Funciona como un encanto.

Sí, eso funciona, con una pequeña advertencia. C# tiene referencias mutables. Así que asegúrate de no hacer algo como esto accidentalmente:

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

Por supuesto, este ejemplo es un poco artificial, pero esto podría suceder cuando se usan referencias mutables. Si utiliza los combinadores de aku's enlaces, esto no será posible.

 13
Author: Tom Lokhorst,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:32

Asumiendo un objeto mítico TreeItem, que conatins una colección de Niños para representar su jerarquía.

    public void HandleTreeItems(Action<TreeItem> item, TreeItem parent)
    {
        if (parent.Children.Count > 0)
        {
            foreach (TreeItem ti in parent.Children)
            {
                HandleTreeItems(item, ti);
            }
        }

        item(parent);
    }

Ahora para llamarlo, pasando la lambda que maneja un elemento, imprimiendo su nombre en la consola.

HandleTreeItems(item => { Console.WriteLine(item.Name); }, TreeItemRoot);
 2
Author: DevelopingChris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-14 05:27:42