【问题标题】:How to transform list of hierarchyid into a binary tree如何将hierarchyid列表转换为二叉树
【发布时间】:2015-11-09 17:17:15
【问题描述】:

我正在做一个多层次的营销(二进制),看起来像这样:

(但二叉树不需要完美,一个节点可以有0-2个孩子)

我的问题是我从数据库中获取的数据是平面列表。

注意我正在使用hierarchyid (sql server 2014)

基本上TextNode 列就像一个面包屑。

每个斜线/ 代表一个level

如果我有 /1/ 的 TextNode 作为根。那么每个以/1/ 开头的节点都属于那个根,它们是/1//1/1//1/1/1/(包括根节点,它将是级别0)

我已经在这个问题中尝试了accepted answer,但它不起作用。

如何将平面列表转换为二叉树,以便轻松遍历并将其显示在屏幕上?

如果重要的话,我正在使用 C#、ASP MVC 5、SQL Server 2014。

【问题讨论】:

    标签: c# asp.net sql-server binary-tree hierarchyid


    【解决方案1】:

    我根据 Alex 实现完全实现了这段代码,但正如在某些情况下提到的那样它不能正常工作..看看我的图像和我的代码(从 Alex 的帖子中复制)[数据库中的数据是正确的但在树视图中似乎有些问题]

    public class Row : IRow<string>
    {
        public string TextNode { get; }
        public string Value { get; }
        public long Id { get; }
        public string FIN { get; }
        public Row(string textNode, string userName, long id, string fin)
        {
            FIN = fin;
            Id = id;
            TextNode = textNode;
            Value = userName;
        }
    }
    
    public interface IRow<out T>
    {
        string TextNode { get; }
        long Id { get; }
        string FIN { get; }
        T Value { get; }
    }
    
    public class TreeNode<T>
    {
        private struct NodeDescriptor
        {
            public int Level { get; }
            public int ParentIndex { get; }
    
            public NodeDescriptor(IRow<T> row)
            {
                var split = row.TextNode.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
                Level = split.Length;
                ParentIndex = split.Length > 1 ? int.Parse(split[split.Length - 2]) - 1 : 0;
            }
        }
        public T title { get; }
        public long Id { get; }
        public string FIN { get; }
        public List<TreeNode<T>> children { get; }
    
        private TreeNode(T value, long id, string fin)
        {
            Id = id;
            FIN = fin;
            title = value;
            children = new List<TreeNode<T>>();
        }
    
        public static TreeNode<T> Parse(IReadOnlyList<IRow<T>> rows)
        {
            if (rows.Count == 0)
                return null;
            var result = new TreeNode<T>(rows[0].Value, rows[0].Id, rows[0].FIN);
            FillParents(new[] { result }, rows, 1, 1);
            return result;
        }
    
        private static void FillParents(IList<TreeNode<T>> parents, IReadOnlyList<IRow<T>> rows, int index, int currentLevel)
        {
            var result = new List<TreeNode<T>>();
            for (int i = index; i < rows.Count; i++)
            {
                var descriptor = new NodeDescriptor(rows[i]);
                if (descriptor.Level != currentLevel)
                {
                    FillParents(result, rows, i, descriptor.Level);
                    return;
                }
                var treeNode = new TreeNode<T>(rows[i].Value, rows[i].Id, rows[i].FIN);
                parents[descriptor.ParentIndex].children.Add(treeNode);
                result.Add(treeNode);
            }
        }
    }
    

    g

    这也是我的 JSON 输出以获取更多信息:

    {"title":"Earth","Id":32,"FIN":"FIN","children":[{"title":"Europe","Id":33,"FIN":"FIN001","children":[{"title":"France","Id":35,"FIN":"FIN001001","children":[{"title":"Paris","Id":36,"FIN":"FIN001001001","children":[]},{"title":"Brasilia","Id":41,"FIN":"FIN002001001","children":[]},{"title":"Bahia","Id":42,"FIN":"FIN002001002","children":[]}]},{"title":"Spain","Id":38,"FIN":"FIN001002","children":[{"title":"Madrid","Id":37,"FIN":"FIN001002001","children":[{"title":"Salvador","Id":43,"FIN":"FIN002001002001","children":[]}]}]},{"title":"Italy","Id":45,"FIN":"FIN001003","children":[]},{"title":"Germany","Id":48,"FIN":"FIN001004","children":[]},{"title":"test","Id":10049,"FIN":"FIN001005","children":[]}]},{"title":"South America","Id":34,"FIN":"FIN002","children":[{"title":"Brazil","Id":40,"FIN":"FIN002001","children":[{"title":"Morano","Id":47,"FIN":"FIN001003001","children":[]}]}]},{"title":"Antarctica","Id":39,"FIN":"FIN003","children":[{"title":"McMurdo Station","Id":44,"FIN":"FIN003001","children":[]}]}]}
    

    【讨论】:

      【解决方案2】:

      这里是一个非常简单的实现(假设节点顺序正确),可以通过多种方式进行增强

      public interface IRow<out T>
      {
          string TextNode { get; }
          T Value { get; }
      }
      
      public class TreeNode<T>
      {
          private struct NodeDescriptor
          {
              public int Level { get; }
              public int ParentIndex { get; }
      
              public NodeDescriptor(IRow<T> row)
              {
                  var split = row.TextNode.Split(new [] {"/"}, StringSplitOptions.RemoveEmptyEntries);
                  Level = split.Length;
                  ParentIndex = split.Length > 1 ? int.Parse(split[split.Length - 2]) - 1 : 0;
              }
          }
      
          public T Value { get; }
          public List<TreeNode<T>> Descendants { get; }
      
          private TreeNode(T value)
          {
              Value = value;
              Descendants = new List<TreeNode<T>>();
          }
      
          public static TreeNode<T> Parse(IReadOnlyList<IRow<T>> rows)
          {
              if (rows.Count == 0)
                  return null;
              var result = new TreeNode<T>(rows[0].Value);
              FillParents(new[] {result}, rows, 1, 1);
              return result;
          }
      
          private static void FillParents(IList<TreeNode<T>> parents, IReadOnlyList<IRow<T>> rows, int index, int currentLevel)
          {
              var result = new List<TreeNode<T>>();
              for (int i = index; i < rows.Count; i++)
              {
                  var descriptor = new NodeDescriptor(rows[i]);
                  if (descriptor.Level != currentLevel)
                  {
                      FillParents(result, rows, i, descriptor.Level);
                      return;
                  }
                  var treeNode = new TreeNode<T>(rows[i].Value);
                  parents[descriptor.ParentIndex].Descendants.Add(treeNode);
                  result.Add(treeNode);
              }
          }
      }
      

      示例用法:

      public class Row : IRow<string>
      {
          public string TextNode { get; }
          public string Value { get; }
      
          public Row(string textNode, string userName)
          {
              TextNode = textNode;
              Value = userName;
          }
      }
      
      class Program
      {
      
          static void Main(string[] args)
          {
              IRow<string>[] rows =
              {
                  new Row("/", "Ahmed"),
                  new Row("/1/", "Saeed"),
                  new Row("/2/", "Amjid"),
                  new Row("/1/1/", "Noura"),
                  new Row("/2/1/", "Noura01"),
                  new Row("/2/2/", "Reem01"),
                  new Row("/1/1/1", "Under_noura")
              };
      
              var tree = TreeNode<string>.Parse(rows);
              PrintTree(tree);
          }
      
          private static void PrintTree<T>(TreeNode<T> tree, int level = 0)
          {
              string prefix = new string('-', level*2);
              Console.WriteLine("{0}{1}", prefix, tree.Value);
              foreach (var node in tree.Descendants)
              {
                  PrintTree(node, level + 1);
              }
          }
      }
      

      【讨论】:

      • 请问有这些案例的例子吗?这个答案有点老了,我可以做得更好,但无论如何它应该可以工作,只需在解析之前对行进行排序(按/ 的数量升序,然后按字符串值)
      • 非常感谢您的跟进。正如你所说,我已经发布了
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-09-24
      • 1970-01-01
      • 1970-01-01
      • 2012-02-28
      • 1970-01-01
      • 2021-06-07
      • 2020-08-24
      相关资源
      最近更新 更多