首页 > 解决方案 > 更新树层次结构中的中间节点

问题描述

我有一个包含字符串属性的节点树层次结构。树层次结构包含一个父子级和该子级的一个子级,依此类推。我必须从列表中找到并更新中间孩子之一的字符串属性,并更新父级及其子级。例如,

 NodeData[] nodes = new NodeData[]
        {
           new NodeData
           {
              Text = "A",
              Children = new NodeData[]
              {
                 new NodeData {
                     Text = "C",
                     Children = new NodeData[]
                     {
                         new NodeData {Text = "AB" }
                     }

                 },
                 new NodeData { Text = "D" },
              }
           },
           new NodeData
           {
              Text = "B",
              Children = new NodeData[]
              {
                 new NodeData
                 {
                    Text = "E",
                    Children = new NodeData[]
                    {
                       new NodeData { Text = "F" },
                    }
                 }
              }
           }
        };

在这种情况下,我必须找到带有文本“AB”的节点,然后更新节点“AB”,但还要更新具有文本“D”、“C”和“A”的 NodeData。我不知道该怎么做,我想保留一个列表,然后通过该列表运行以更新相关字段。

标签: c#linqrecursion

解决方案


这是我对解决方案的尝试。

给定看起来像这样的树:

A
    C
        AB
        AC
    D
B
    E
        F

并且鉴于需要更新针节点的所有直接兄弟节点和所有父节点(包括它们的兄弟节点),这是我的代码:

using System;
using System.Linq;

namespace Ns
{
    internal static class Program
    {
        private static void Main(string[] args)
        {
            var nodes = new[]
            {
                new NodeData("A",
                    new NodeData("C",
                        new NodeData("AB"),
                        new NodeData("AC")),
                    new NodeData("D")),
                new NodeData("B",
                    new NodeData("E",
                        new NodeData("F")))
            };
            FindAndUpdateAscendingly(nodes, "AB", x => Console.WriteLine(x.Text));
        }

        private static void FindAndUpdateAscendingly(NodeData[] rootNodes, string dataToFind, Action<NodeData> callback)
        {
            bool FindAndAscend(NodeData[] nodes)
            {
                var needleIsFound = nodes.Any(x => x.Text == dataToFind || FindAndAscend(x.Children));
                if (needleIsFound)
                {
                    foreach (var nodeData in nodes)
                    {
                        callback(nodeData);
                    }
                }

                return needleIsFound;
            }

            FindAndAscend(rootNodes);
        }
    }


    internal class NodeData
    {
        public NodeData(string text, params NodeData[] children)
        {
            Text = text;
            Children = children ?? Array.Empty<NodeData>();
        }

        public string Text { get; }
        public NodeData[] Children { get; }
    }
}

它的要点在于FindAndUpdateAscendingly函数。您将一个节点数组传递给它,一个您想要查找的字符串,以及一个您想要在您想要更新的每个节点上调用的函数。

目前,我将 aConsole.WriteLine作为假的“更新”函数传递,只是为了说明迭代顺序。这是打印的节点迭代顺序:

AB
AC
C
D
A
B

基本上,它使用您指定的文本搜索节点,然后冒泡并调用callback所有父节点及其兄弟节点。这就是为什么你不触摸EF节点。

对于真实数据和实际使用,Console.WriteLine您将传递一个实际上对 NodeData 做了某些事情的函数,而不是传递 。例如,像这样:

FindAndUpdateAscendingly(nodes, "AB", node =>
{
    node.Text += " - processed";
    Console.WriteLine(node.Text);
});

推荐阅读