JS从一组URL创建树

时间:2019-11-10 00:31:56

标签: javascript data-structures tree

我很难从给定的URL数组创建树。 主要目标是将网址分为多个部分,然后将其排列为父子对象。 例如,给定数组:

   const data =  [
        {
            'id': '1',
            'name': '/home',
        },
        {
            'id': '2',
            'name': '/story',
        },
        {
            'id': '3',
            'name': '/story/summer-story',
        },
        {
            'id': '4',
            'name': '/story/summer-story/2019',
        },
    ]

输出应为:

const tree = [
    {
        'id': '1',
        'name' : '/home',
        children: []
    },
    {
        'id': '2',
        'name': '/story',
        'children': [
            {
                'id' : '3',
                'name': '/story/summer-story',
                'children': [
                    {
                        'id': '4',
                        'name': '/story/summer-story/2019'
                    }
                ]
            },
        ]
    }
]

我已经使用Javascript deriving a Tree from a set of URLs

中的示例创建了某种解决方案

当URL有一个或两个段时,我目前的解决方案很好用。一旦它具有两个以上的段,它将在根级别上添加节点,而不是嵌套到下降的父节点中。

示例代码

export const addToTree = (node, treeNodes) => {
    const parentNode = getTheParentNodeChildArray(node.name, treeNodes) || treeNodes;

    parentNode.push({
        title: node.title,
        name: node.name,
        children: []
    });
};

export const getTheParentNodeChildArray = (path, treeNodes) => {
    for (let i = 0; i < treeNodes.length; i++) {
        const treeNode = treeNodes[i];

        const lastSegment = getStringWithoutLastSegment(path);
        const lastNode = getStringWithoutLastSegment(treeNode.name);

        if (lastNode === lastSegment) {
            return treeNode.children;
        }
        else if (treeNode.children.length > 0) {
            let possibleParent = false;

            treeNode.children.forEach(function(item) {
                const lastSegmentPath = getStringWithoutLastSegment(path);
                const lastSegmentItem = getStringWithoutLastSegment(item.name);

                if (lastSegmentItem === lastSegmentPath) {
                    possibleParent = true;
                    return false;
                }
            });

            if (possibleParent) {
                return getTheParentNodeChildArray(path, treeNode.children);
            }
        }
    }
};

export const createTree = (nodes) => {
    const tree = [];

    for (let i = 0; i < nodes.length; i++) {
        const node = nodes[i];
        addToTree(node, tree);
    }
    return tree;
};

export const getStringWithoutLastSegment = (str) => {
    const stringArray = str.split('/');
    stringArray.pop();
    return (stringArray.join('/'));
};

提前谢谢

1 个答案:

答案 0 :(得分:2)

这可以直接在一个函数中完成。该方法涉及遍历要添加的所有节点,然后逐目录遍历树目录,并根据需要创建节点。最终结果不是一棵树,因为有多个根,但是在构造它时使用虚拟根会很有帮助。

const makeTree = data => {
  const base = {children: []};
  
  for (const node of data) {
    const path = node.name.match(/\/[^\/]+/g);
    let curr = base;
    
    path.forEach((e, i) => {
      const currPath = path.slice(0, i + 1).join("");
      const child = curr.children.find(e => e.name === currPath);
      
      if (child) {
        curr = child;
      }
      else {
        curr.children.push({
          id: node.id, name: currPath, children: []
        });
        curr = curr.children[curr.children.length-1];
      }
    });
  }
  
  return base.children;
};

const data = [
  {
    'id': '1',
    'name': '/home',
  },
  {
    'id': '2',
    'name': '/story',
  },
  {
    'id': '3',
    'name': '/story/summer-story',
  },
  {
    'id': '4',
    'name': '/story/summer-story/2019',
  },
];

console.log(makeTree(data));