【问题标题】:Dynamically create multidimensional array from split input从拆分输入动态创建多维数组
【发布时间】:2021-09-19 20:43:49
【问题描述】:

我有一个对象数组,它们都有一个路径和一个名称属性。 喜欢

[
{
 "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 属性吗?
  • 这对于输出来说是不够的。我拥有的数据是我编写的第一个数据类型的数组,即 json 格式的数组。但最好知道path 中的结束整数始终与当前id 相同
  • 你不能有更多的根路径,比如{id:2, path :'2', name: 'other root'},对吧?
  • 这些叶子节点即1278能否存在于多条路径下?换句话说,带有id 1278 的“Superbig T-Rex”是否可以同时存在于动物和玩具之下..?我问的原因是,如果不能,那么我们可以丢弃 path 并切换到 parent 结构,这可能会减轻工作。
  • 路径的最后一部分,即注释 2 的 id 不会出现在我认为的其他地方

标签: javascript arrays typescript


【解决方案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
  • 我认为这就是我的 Nederländerna。 2Ill 测试并返回结果
  • *不需要Nederländerna
【解决方案2】:

假设根始终是相同的,我想出了这段代码,我花了一些时间,但想想还是很有趣的。

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"
}

我认为在这里有更多的根可能需要一些修复。虽然我认为如果我们谈论多个根,问题会有所不同,因为您的数据变量是一个对象

另外,如果你以递归的方式思考,它可能更容易理解,但性能上没有 cmets。

【讨论】:

    猜你喜欢
    • 2022-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-23
    • 2014-08-14
    相关资源
    最近更新 更多