【问题标题】:Recursive tree creation递归树创建
【发布时间】:2021-01-20 14:43:10
【问题描述】:

我在 C# 中有一个 Node 类,具有以下属性:

public class Node
{
   public int Id {get;set;}
   public int? ParentId {get;set;}
   public string Label {get;set;}
}

我有一个TreeView 控件,它提供以下创建方法 一个新节点:

MyTreeView.CreateNode(key, label);
parent.Nodes.CreateNode(key, label);

如果我想添加一个新的子节点,我需要使用第二种方法,否则使用第一种。两者都返回TreeNode 类型的对象。

考虑到根节点具有ParentId = null,您将如何在 C# 中创建递归函数来填充树视图?

这是我到目前为止所做的:

// create a list of root nodes
var roots = myList.Where(x => x.ParentId == null);
// send the roots to a recursive func
foreach(var root in roots)
{
   AddNode(null,root,myList);
}

这是我的递归函数:

private void AddNode(Node parent, Node current, IList<Node> items)
{
   TreeNode treenode = null;
   if(parent == null)
   {
      treenode = mytree.CreateNode(current.Id.ToString(), current.Label);
   }else{
      var parentnode = mytree.GetNode(parent.Id.ToString());
      treenode = parentnode.Nodes.CreateNode(current.Id.ToString(), current.Label);
   }
   // call the recursion for the children
   var children = items.Where(x => x.ParentId == current.Id);
   foreach(var child in children)
   {
      AddNode(current, child, items);
   }
}

【问题讨论】:

  • 你需要添加C#标签。如果这是作业,您也应该添加作业标签。此外,您应该向我们展示您尝试过的代码示例。
  • 好的,我会修改帖子,谢谢。
  • 这个函数有什么问题?除了你不需要变量 treenode
  • 这是错误的,因为我必须在一个电话中完成所有事情,我在这里做的是两个电话。我想用 LinQ 添加一个扩展,但我不太擅长。
  • 你忘了提一些我觉得很重要的事情。您正在根据某种IList 生成您的树,您的列表中有什么?可以做出推断,但不能确定

标签: c# recursion


【解决方案1】:

如果您的树视图控件是从 System.Windows.Forms.TreeView 派生的,您可以替换

MyTreeView.CreateNode(key, label);
parent.Nodes.CreateNode(key, label);

MyTreeView.Nodes.Add(key, label);
parent.Nodes.Add(key, label);

所以调用总是转到 TreeNodeCollection 类型的节点集合。现在,您可以使用 Nodes 集合作为参数,而不是您的 Node 对象。

var roots = myList.Where(x => x.ParentId == null);
foreach (var root in roots)
{
    AddNode(mytree.Nodes, root, myList);
}

private void AddNode(TreeNodeCollection nodes, Node current, IList<Node> items)
{
    TreeNode treenode = nodes.Add(current.Id.ToString(), current.Label);

    var children = items.Where(x => x.ParentId == current.Id);
    foreach (var child in children)
    {
        AddNode(treenode.Nodes, child, items);
    }
}

这有两个好处:

  1. 您无需每次都查找父级。
  2. 您只有一个调用 (TreeNodeCollection.Add)。

但是,如果您无法在每个根的 AddNode 调用中访问 TreeView.Nodes 集合,则必须在 AddNode 方法的顶部进行检查。

var roots = myList.Where(x => x.ParentId == null);
foreach (var root in roots)
{
    AddNode(null, root, myList);
}

private void AddNode(TreeNodeCollection nodes, Node current, IList<Node> items)
{
    if (nodes == null)
    {
        nodes = myTree.Nodes;
    }

    ...
}

【讨论】:

    【解决方案2】:

    试试这个代码:

    var lookup = myList.ToLookup(n => n.ParentId.ToString());
    
    Action<IEnumerable<TreeNode>> addChildren = null;
    addChildren = tns =>
    {
        var query =
            from tn in tns
            from cn in lookup[tn.Name]
            select tn.Nodes.CreateNode(cn.Id.ToString(), cn.Label);
        var nodes = query.ToArray();
        if (nodes.Length > 0)
        {
            addChildren(nodes);
        }
    };
    
    addChildren(
        lookup[null]
            .Select(n =>
                MyTreeView.CreateNode(n.Id.ToString(), n.Label)));
    

    我无法对其进行全面测试,因此您可能需要更改一些代码才能使其正常工作,但应该相当接近。

    【讨论】:

      【解决方案3】:

      我可能会做这样的事情......

      public class Node
      {
          public int Id { get; set; }
          public int? ParentId { get; set; }
          public string Label { get; set; }
      
          public Node(int? parentId, int id, string label)
          {
              ParentId = parentId;
              Id = id;
              Label = label;
          }
      }
      
      public class TreeNode : List<TreeNode>
      {
          public string Key { get; set; }
          public string Label { get; set; }
      
      
          public IEnumerable<TreeNode> Descendants
          {
              get
              {
                  yield return this;
      
                  foreach (var child in this)
                  {
                      foreach (var descendant in child.Descendants)
                      {
                          yield return descendant;
                      }
      
                  }
              }
          }
      
          public TreeNode(string key, string label)
          {
              Key = key;
              Label = label;
          }
      
          public void CreateNode(int id, string label)
          {
              Add(new TreeNode(id.ToString(), label));
          }
      }
      
      public class Tree
      {
          private TreeNode _root = new TreeNode(null, null);
      
          public Tree(IEnumerable<Node> nodes)
          {
              nodes.ToList().ForEach(node => CreateNode(node.ParentId, node.Id, node.Label));
          }
      
          public void CreateNode(int? parentId, int id, string label)
          {
              if (parentId == null)
              {
                  _root.CreateNode(id, label);
              }
              else
              {
                  _root.Descendants.First(x => x.Key == parentId.ToString()).CreateNode(id, label);
              }
          }
      
          public IEnumerable<TreeNode> Descendants => _root.Descendants;
      }
      

      【讨论】:

        【解决方案4】:

        试试这个代码:

        Node{
             Id, Label, List<Tree> Children
        }
        
        Tree GetTree(id){
             var node=new Node();
             
             node.Id=id;
             node.Children=new List<Node>();
             
             List<Node> children = db.Nodes.Where(x => x.ParentId==id);
             
             foreach(child in children){
                   var childTree=GetTree(child.Id);
                   node.Children.Add(childTree);
             }
             
             return node;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-01-02
          • 2011-05-08
          • 2015-03-18
          • 2017-09-21
          • 2012-08-23
          相关资源
          最近更新 更多