从分割输入动态创建多维数组

7

我有一个对象数组,每个对象都有路径和名称属性。例如:

[
{
 "id": "1",
 "path": "1",
 "name": "root"
},
{
 "id": "857",
 "path": "1/857",
 "name": "Animals"
},
{
 "id": "1194",
 "path": "1/857/1194",
 "name": "Dinasours"
},
...and so on
]

这里是一些路径示例

1/1279/1282
1/1279/1281
1/1279/1280
1/857
1/857/1194
1/857/1194/1277
1/857/1194/1277/1278

我想将此转化为多维数组,例如:

const data = {
  id: "1",
  name: "Root",
  children: [
    {
      id: "1279",
      name: "Toys",
    },
    {
      id: "857",
      name: "Animals",
      children: [
        {
          id: "1194",
          name: "Dinasours",
          children: [
            {
              id: "1277",
              name: "T-Rex",
              children: [
                {
                  id: "1278",
                  name: "Superbig T-Rex",
                },
              ],
            },
          ],
        },
      ],
    },
  ],
};

你可以理解这个数据量是更大的。

有没有一种简洁的方式来转换这些数据?


你想要转换每个 id 属性吗? - captain-yossarian from Ukraine
这还不够产生输出。我拥有的数据是我写的第一个数据类型的数组,就是JSON中的那个。但是知道path中的最后一个整数始终与当前的id相同可能会很有用。 - Niklas Fondberg
你不能有多个根路径,例如 {id:2, path :'2', name: 'other root'},对吧? - Gabriele Petrioli
这些叶节点(即1278)可以存在于多个路径下吗?换句话说,“超级巨型霸王龙”(id为1278)可以同时存在于动物和玩具类别下吗?我之所以问是因为,如果不能,则我们可以删除“路径”并转换为“父级”结构,这可能会使工作更容易。 - Redu
路径的最后一部分是笔记的ID,我认为不会出现在其他地方。 - Niklas Fondberg
2个回答

1
假设根节点始终相同,我想出了这段代码,虽然花费了一些时间,但思考它还是很有趣的。
var data = {};

list.forEach(item => {
  var path = item.path.split("/");
  
  let parent = data;
  
  path.forEach((id) => {
    if (!parent.id) {
      parent.id = id;
      parent.children = [];

      if (id != item.id) {
        let next = {}
        parent.children.push(next);
        parent = next;        
      }

    } else if (parent.id != id) {
      let next = parent.children.find(child => child.id == id);

      if (!next) {
        next = { id: id, children: [] }
        parent.children.push(next);
      }
      
      parent = next;
    }
  });
  
  parent.id = item.id;
  parent.name = item.name
});

输出:

{
  "id": "1",
  "children": [
    {
      "id": "857",
      "children": [
        {
          "id": "1194",
          "children": [
            {
              "id": "1277",
              "children": [
                { "id": "1278", "children": [], "name": "Superbig T-Rex" }
              ],
              "name": "T-Rex"
            }
          ],
          "name": "Dinasours"
        }
      ],
      "name": "Animals"
    },
    { "id": "1279", "children": [], "name": "Toys" }
  ],
  "name": "Root"
}

我认为在此处拥有更多的根可能需要一些修复。虽然如果我们谈论多个根,问题可能会有所不同,因为您的数据变量是一个对象。
另外,如果您以递归方式思考,它可能更易理解,但对性能没有评论。

1

我想知道这是否足以满足你的需求?

我将把对象称为节点(只是因为我是图论专家,这就是我的做法)。

  1. 使用Map构建索引,将每个id映射到对象本身。 (纯粹出于效率考虑。您可以在每次需要时通过id从头开始找到每个节点。)
  2. 拆分路径以获取倒数第二个路径片段,这应该是节点直接父级的id。(假设只有一个,并且保证存在对应于该id的节点?)
  3. 将子项添加到父项的子项列表中。 我们会小心不要多次添加它。

这将导致没有子项的节点实际上没有children属性(而不是具有仅为[]children属性)。 我也没有从对象中删除path属性。

作为一种谨慎的注意事项,如果存在没有相应对象的路径片段,则此方法将无法正常工作。

const nodes = [
  { id: '1', path: '1', name: 'root' },
  { id: '857', path: '1/857', name: 'Animals' },
  { id: '1194', path: '1/857/1194', name: 'Dinasours' }
  //...and so on
];

const index = new Map();
for (let node of nodes) {
  index.set(node.id, node)
}
for (let node of nodes) {
  const fragments = node.path.split('/');
  const parentId = fragments[fragments.length - 2];
  const parent = index.get(parentId);
  if (parent !== undefined) {
    parent.children = parent.children || [];
    if (!parent.children.includes(node)) {
      parent.children.push(node);
    }
  }
}

// TODO: Decide which node is the root.
// Here's one way to get the first (possibly only) root.
const root = index.get(nodes[0].path.split('/')[0]);

console.dir(root, { depth: null });


根目录当前始终为1。 - Niklas Fondberg
我认为这就是我在荷兰所需要的。我会测试并回来报告结果。 - Niklas Fondberg
不需要荷兰。 - Niklas Fondberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接