【问题标题】:Build tree from table从表构建树
【发布时间】:2014-05-08 18:36:18
【问题描述】:

我定义了以下类 Node 以获取父/子关系

class Node
{
        public int Id { get; set; }
        public int? ParentId { get; set; }
        public string Operator { get; set; }
        public string Sign { get; set; }
        public Node Parent { get; set; }
        public IList<Node> Children { get; set; }

        public Node()
        {
            Children = new List<Node>();
        }

        public override string ToString()
        {
            //return "Node: " + Operator + " " + Id + " " + string.Join(",", Children.Select(x => x.Id));
            return "Node: " + Operator + " " + Id + " "
            + string.Join(",", Children.Select(x => string.Format("({0}, {1})", x.Sign, x.Id)));
        }
}

我以下表为例

PNLId   PNLCode PNLParentId Operator    Sign
0      
49  C   51  +   NULL
50  Z   51  +   NULL
51  Y   107 /   NULL
52  B   107 /   NULL
53  B   108 +   NULL

我在 main 中编写了以下脚本:

var map = new Dictionary<int, Node>();
var rootNodes = new List<Node>();

foreach (DataRow row in dt.Rows)
{
    int id = Convert.ToInt32(row["PNLId"]);
    int? parentId = null;
    if (!row.IsNull("PNLParentId"))
    {
        parentId = Convert.ToInt32(row["PNLParentId"]);
    }
    string op = Convert.ToString(row["Operator"]);
    string sign = Convert.ToString(row["Sign"]);
    map[id] = new Node
    {
        Id = id,
        ParentId = parentId,
        Operator = op,
        Sign=sign

    };
}

foreach (var pair in map)
{
    if (pair.Value.ParentId.HasValue)
    {
        var parent = map[pair.Value.ParentId.Value];
        pair.Value.Parent = parent;
        parent.Children.Add(pair.Value);
        parent.Operator = pair.Value.Operator;
    }
    else
    {
        rootNodes.Add(pair.Value);

    }
}

在这种情况下,它将返回 ,对于 PNLParentId 107

[107 Node: + 107 (, 51),(, 52)]  

应该是哪里错了

[107 Node: / 107 (, 51),(, 52)]

如何修改上面的代码以先构建节点树。然后从根节点开始从子节点复制运算符。进度到孩子并复制他们孩子的操作符?

【问题讨论】:

    标签: c#


    【解决方案1】:

    我已经修复了您为构建树而编写的代码。 这是一些可以使用的测试数据(我没有你拥有的数据库表):

    var map = new Node[] {
        new Node() { Id=0, ParentId=0, Operator="", Sign=null}
        ,new Node() { Id=1, ParentId=null, Operator="+", Sign=null}
        ,new Node() { Id=2, ParentId=3, Operator="+", Sign=null}
        ,new Node() { Id=3, ParentId=4, Operator="/", Sign=null} 
        ,new Node() { Id=4, ParentId=4, Operator="/", Sign=null} 
        ,new Node() { Id=5, ParentId=1, Operator="+", Sign=null} 
    };
    

    这里是固定代码:

    // remove Value
    var rootNodes = new List<Node>();
    foreach (var pair in map)
    {
        if (pair.ParentId.HasValue) 
        {
            var parent = map[pair.ParentId.Value]; 
            pair.Parent = parent; 
            parent.Children.Add(pair);
            parent.Operator = pair.Operator;
        }
        else
        {
            rootNodes.Add(pair);    
        }
    }
    

    变化是:

    • 添加了根节点
    • 已删除 .Value

    运行后,rootNodes 集合将包含 1 个元素(Id=1 的那个),并且映射数组将包含对其父对象的正确对象引用。

    说明:

    pair 变量属于foreach 循环并包含map 的元素。 变量mapNode 对象的数组,这是一个您在其中声明了属性Parent 的类——它也是Node 类型。

    Node 类型的变量都是对象类型,而不是值类型,因此它们不拥有.Value 属性。 但是您声明的 ParentId 是可空值类型,因为声明 int? - 并且所有 nullable 值类型(注意 ? 后缀)都有 .Value财产: 因此对于ParentId,您可以使用ParentId.Value(和.HasValue 来检查是否为空)来获取值,但对于Parent 则不能,它是一个Node 对象。 Node对象的属性需要通过属性名直接访问。

    【讨论】:

    • 为什么要删除 .Value ?我没听懂。
    • @user3548593:我已经编辑了 user3615347 的答案并添加了解释。希望对您有所帮助。
    • @user3548593:您可以在LinqPad(一个免费的工具)中测试此答案中的代码-只需将其放入main()方法中,在末尾添加rootNodes.Dump(); map.Dump();,然后从您的问题中添加 Node 类。如果您运行示例,您会在输出窗口中看到正在构建的递归结构:.Dump() 方法 LinqPad 提供的好处之一!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多