【问题标题】:Building nested lists from ancestor data?从祖先数据构建嵌套列表?
【发布时间】:2018-04-23 13:22:23
【问题描述】:

给定结构:

{
    id: 'id-1',
    name: 'name1',
    ancestors: []
},{
    id: 'id-2',
    name: 'name2',
    ancestors: []
},{
    id: 'id-3',
    name: 'name3',
    ancestors: ['id-1']
},{
    id: 'id-4',
    name: 'name4',
    ancestors: ['id-3', 'id-1']
}
  • 假设它们没有以任何有意义的方式排序。
  • 祖先字段是一个数组,显示到顶层的路径。

构建嵌套列表 (ul) 的最有效方法是什么?

我的第一个想法是递归方法,但这似乎很麻烦,因为它会重复搜索整个列表。因为这将是在浏览器中运行的 javascript 解决方案,可能会出现问题。

【问题讨论】:

  • 如何构建树后端?
  • 一个元素怎么会有多个祖先?
  • @Cid nodejs?!?!
  • @JonasW。不管是什么语言,如果它是一个客户端-服务器应用程序,他可以构建树服务器端
  • 我们是否假设ancestors 数组中的字符串将是现有对象的ID?例如,是否存在对象不存在的字符串 id?另外如何读取ancestors 数组?您可以发布问题中提供的示例的预期输出吗?

标签: javascript algorithm tree


【解决方案1】:

您可以构建一棵树,然后渲染一个嵌套列表。

function getTree(data) {
    var o = {};
    data.forEach(function (a) {
        var parent = a.ancestors[0];
        if (o[a.id] && o[a.id].children) {
            a.children = o[a.id].children;
        }
        o[a.id] = a;
        o[parent] = o[parent] || {};
        o[parent].children = o[parent].children || [];
        o[parent].children.push(a);
    });
    return o.undefined.children;
}

function buildList(tree, target) {
    var ul = document.createElement('ul');
    tree.forEach(o => {
        var li = document.createElement('li');
        li.appendChild(document.createTextNode(o.name));
        buildList(o.children || [], li);
        ul.appendChild(li);
    });
    target.appendChild(ul);
}

var data = [{ id: 'id-1', name: 'name1', ancestors: [] }, { id: 'id-2', name: 'name2', ancestors: [] }, { id: 'id-3', name: 'name3', ancestors: ['id-1'] }, { id: 'id-4', name: 'name4', ancestors: ['id-3', 'id-1'] }],
    tree = getTree(data);

console.log(tree);
buildList(tree, document.body);

【讨论】:

  • 所以如果我没看错的话,这将只需要一个循环遍历对象,但需要大量空间,因为每个项目将存在多次。所以它的计算复杂度很低,但空间复杂度很高?
  • 不,一个项目只存在一次。参考经常存储。如果你看一下o,那么你会得到里面的所有父节点和节点以及嵌套的子节点,它们是对单个对象的引用。
【解决方案2】:

构建地图以加快查找速度:

 const byId = new Map(array.map(el => ([el.id, el]));

那么创建嵌套树非常简单,我们只需检查一个节点是否没有祖先,然后它是根元素,否则我们将其添加为父节点的子节点:

 const root = [];

 for(const obj of array) {
   if(obj.ancestors.length) {
     const parent = byId.get(obj.ancestors[0]);
     if(parent.children) {
       parent.children.push(obj);
     } else {
       parent.children = [obj];
     }
   } else {
    root.push(obj);
   }
 }

所以现在root 包含一个嵌套树,你可以使用递归的方式来遍历它:

 function traverse(elements) {
    for(const el of elements) {
      // Render ...
      traverse(el.children || []);
    }
 }

 traverse(root);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-20
    • 2022-08-03
    • 2019-05-20
    相关资源
    最近更新 更多