【问题标题】:Updating the middle node in a Tree Heirarchy更新树层次结构中的中间节点
【发布时间】:2020-01-04 22:03:03
【问题描述】:

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

 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。我不知道该怎么做,我想保留一个列表,然后通过该列表运行以更新相关字段。

【问题讨论】:

  • 如果有一个“AB”级别的兄弟节点,比如“AC”,你是否也需要更新它?还是一找到“AB”就需要升到父级?
  • 是的,我需要
  • 您始终可以将父属性放入一个节点中,这样您就可以在树中上下移动。在某些项目中,我还制作了一个 List ,这样我就可以按顺序访问数据以及访问树。列表不会复制节点,而是通过引用访问节点,因此对节点的任何更改都会更新树和列表。

标签: c# linq recursion


【解决方案1】:

这是我的解决方案。

给定的树看起来像这样:

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 函数。您将一个节点数组传递给它,一个您想要查找的字符串,以及一个您想要在您想要更新的每个节点上调用的函数。

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

AB
AC
C
D
A
B

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多