从具有父字段的平面列表构造层次结构树? [复制]

Posted

技术标签:

【中文标题】从具有父字段的平面列表构造层次结构树? [复制]【英文标题】:Construct hierarchy tree from flat list with parent field? [duplicate] 【发布时间】:2014-03-13 02:06:33 【问题描述】:

我有一个带有parent 字段的“页面”对象列表。此父字段引用列表中的另一个对象。我想根据这个字段从这个列表中创建一个树层次结构。

这是我的原始列表的样子:

[
  
    id: 1,
    title: 'home',
    parent: null
  ,
  
    id: 2,
    title: 'about',
    parent: null
  ,
  
    id: 3,
    title: 'team',
    parent: 2
  ,
  
    id: 4,
    title: 'company',
    parent: 2
  
]

我想把它转换成这样的树形结构:

[
  
    id: 1,
    title: 'home',
    parent: null
  ,
  
    id: 2,
    title: 'about',
    parent: null,
    children:  [
      
        id: 3,
        title: 'team',
        parent: 2
      ,
      
        id: 4,
        title: 'company',
        parent: 2
      
    ]
]

我希望有一个可重用的函数,我可以随时针对任意列表调用它。有人知道处理这个问题的好方法吗?任何帮助或建议将不胜感激!

【问题讨论】:

【参考方案1】:
function treeify(list, idAttr, parentAttr, childrenAttr) 
    if (!idAttr) idAttr = 'id';
    if (!parentAttr) parentAttr = 'parent';
    if (!childrenAttr) childrenAttr = 'children';

    var treeList = [];
    var lookup = ;
    list.forEach(function(obj) 
        lookup[obj[idAttr]] = obj;
        obj[childrenAttr] = [];
    );
    list.forEach(function(obj) 
        if (obj[parentAttr] != null) 
            if (lookup[obj[parentAttr]] !== undefined) 
                lookup[obj[parentAttr]][childrenAttr].push(obj);
             else 
                 //console.log('Missing Parent Data: ' + obj[parentAttr]);
                 treeList.push(obj);
                           
         else 
            treeList.push(obj);
        
    );
    return treeList;
;

Fiddle

【讨论】:

请记住,上面的答案使用了两个循环,因此可以改进。由于我找不到实现 O(n) 解决方案的 npm 模块,因此我创建了以下模块(单元测试,100% 代码覆盖率,大小只有 0.5 kb 并且包括类型。也许它可以帮助某人:npmjs.com/package /performant-array-to-tree @PhilipStanislaus:O(2n) = O(n)。我的解决方案也是O(n)。我承认我没有达到速度记录。可以测量我的版本还是您的版本更快(两个简单循环与一个复杂循环),但我无法先验地判断哪个更快。但是,它们的时间复杂度完全相同 @Amadan 感谢您的想法。你是对的,他们的时间复杂度是相等的。我发布了链接,以防有人对 npm 包中的高效实现感兴趣。 因为我的 npm 包performant-array-to-tree 收到了很多下载,所以我在 npm 上编写了一些可用包的基准测试。请在此处找到结果:github.com/philipstanislaus/array-to-tree-benchmarks。如果您有兴趣,很高兴添加其他人!【参考方案2】:

接受的答案对我的研究非常有帮助,但是,我必须在心里解析 id 参数,我理解这会使函数更灵活,但对于算法新手来说可能有点难以推理。

如果其他人遇到这个困难,这里的代码基本相同,但可能更容易理解:

const treeify = (arr, pid) => 
  const tree = [];
  const lookup = ;
  // Initialize lookup table with each array item's id as key and 
  // its children initialized to an empty array 
  arr.forEach((o) => 
    lookup[o.id] = o;
    lookup[o.id].children = [];
  );
  arr.forEach((o) => 
    // If the item has a parent we do following:
    // 1. access it in constant time now that we have a lookup table
    // 2. since children is preconfigured, we simply push the item
    if (o.parent !== null) 
      lookup[o.parent].children.push(o);
     else 
      // no o.parent so this is a "root at the top level of our tree
      tree.push(o);
    
  );
  return tree;
;

它与一些 cmets 接受的答案相同,用于解释发生了什么。这是一个用例,它会根据级别生成一个 div 列表,其中包含内联 marginLeft 缩进的页面:

const arr = [
  id: 1, title: 'All', parent: null,
  id: 2, title: 'Products', parent: 1,
  id: 3, title: 'Photoshop', parent: 2,
  id: 4, title: 'Illustrator', parent: 2,
  id: 4, title: 'Plugins', parent: 3,
  id: 5, title: 'Services', parent: 1,
  id: 6, title: 'Branding', parent: 5,
  id: 7, title: 'Websites', parent: 5,
  id: 8, title: 'Pen Testing', parent: 7];
const render = (item, parent, level) => 
  const div = document.createElement('div');
  div.textContent = item.title;
  div.style.marginLeft = level * 8 + 'px';
  parent.appendChild(div);
  if (item.children.length) 
    item.children.forEach(child => render(child, div, ++level));
  
  return parent;

const fragment = document.createDocumentFragment();
treeify(arr)
  .map(item => render(item, fragment, 1))
  .map(frag => document.body.appendChild(frag))

如果你想运行 Codepen:https://codepen.io/roblevin/pen/gVRowd?editors=0010

在我看来,这个解决方案的有趣之处在于,查找表使用项目的 ID 作为键保持平坦,并且只有根对象被推入结果树列表。然而,由于 javascript 对象的引用性质,根有它的孩子,孩子有他们的孩子,等等,但它本质上是从根连接起来的,因此是树状的。

【讨论】:

以上是关于从具有父字段的平面列表构造层次结构树? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

iOS:转储视图和约束的层次结构树

XCUITest - 选定的单元格未显示在 iOS 15 的层次结构树中

org-mode,如何使用格式良好的组织链接自动生成漂亮的文件层次结构树

数据结构(11)---二叉树

数字IC验证学习,uvm资源库uvm componentuvm平台的结构树

图解数据结构树之AVL树