Pregunta

Alguien puede mostrarme cómo implementar un recursiva expresión lambda para recorrer una estructura de árbol en C#.

¿Fue útil?

Solución

Ok, he encontrado algo de tiempo libre por fin.
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);

Otros consejos

Una solución adecuada, y de hecho la idiomáticas solución en muchos lenguajes de programación funcional, sería el uso de un punto fijo combinator.En pocas palabras:un punto fijo de combinador de respuestas a la pregunta "¿cómo puedo definir una función anónima para ser recursivo?".Pero la solución es tan trivial que todo los artículos están escritos para explicar ellos.

Un sencillo, pragmático alternativa es "regrese en el tiempo" a las travesuras de C:declaración antes de la definición.Pruebe las siguientes (el "factorial" de la función):

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

Funciona como un encanto.

O, para una pre-orden del árbol de recorrido en un objeto de la clase TreeNode que implementa IEnumerable<TreeNode> adecuadamente para que vaya a través de sus hijos:

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

Una alternativa sencilla es que "regrese en el tiempo" a las travesuras de C y C++:declaración antes de la definición.Intente lo siguiente:

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

Funciona como un encanto.

Sí, que hace el trabajo, con una pequeña salvedad.C# tiene mutable referencias.Así que asegúrese de no querer hacer algo como esto:

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 ocurrir cuando se utiliza mutable referencias.Si utiliza los combinadores de aku's de los enlaces, esto no será posible.

Suponiendo un mítico objeto TreeItem, que contiene una colección para Niños de representar a 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 llamar, pasando la lambda que se encarga de un artículo, mediante la impresión de su nombre a la consola.

HandleTreeItems(item => { Console.WriteLine(item.Name); }, TreeItemRoot);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top