将相关元素嵌套在一起,父/子

问题描述 投票:0回答:1

假设我的对象也有一个数组:

[
  {
    "id": "5a97e047f826a0111b754beb",
    "name": "Hogwarts",
    "parentId": "5c7bf2191d41c810b2ad6186",
    "childrenIds": []
  },
  {
    "id": "5c7bf2191d41c810b2ad6186",
    "name": "Defense Against The Dark Arts",
    "parentId": null,
    "childrenIds": [
      "5a97e047f826a0111b754beb"
    ]
  }
]

我想做的是一个函数,该函数返回另一个数组,但是这次只包含没有将parentID作为根元素,并且在其上具有包含其子代的子代数组的项目,因此到达有一个空的childrenIDs数组。 (还要删除父/子id属性)

对于先前的输入,我将返回类似的内容

[
  {
    "id": "5c7bf2191d41c810b2ad6186",
    "name": "Defense Against The Dark Arts",
    "children": [
      {
        "id": "5a97e047f826a0111b754beb",
        "name": "Hogwarts"
      }
    ]
  }
]

我似乎无法想到该任务的任何有效代码,任何人都可以帮忙吗?

javascript arrays sorting
1个回答
0
投票

您可以通过对象中的ID保留对每个节点的引用,并在运行时构建树。由于我们可能会遇到对我们尚未看到的条目的引用,因此我们将在此期间创建存根(仅由子数组组成),并在以后将其替换为实际的存根。

似乎您有一个垂直的双向链接列表,既将父级ID保存在子级中,又将子级ID保存在父级中,但是我们只需要其中一个即可构建树。我们将使用存储在每个孩子中的父母ID。 (请注意,这是假设您的结构是一致的,没有不平衡的关系或悬挂的引用。)

为简单起见,我们创建一个根节点,最后将返回其子节点,这样我们就不必在没有父节点的情况下处理节点。

然后您可以编写如下代码:

function makeTree (rows) {
  // Use a symbol to denote the root ID to avoid clashes with any real IDs
  const ROOT = Symbol('ROOT')

  // Node index, by ID
  // Add a root node from the start
  const nodes = { [ROOT]: { children: [] } }

  // Helper function to return an existing node or create a stub if not existing
  const getNodeOrCreateStub = id => nodes[id] || (nodes[id] = { children: [] })

  for (const row of rows) {
    // Add current row to index, merging data with existing stub, if any.
    // This keeps any existing references in other nodes' children arrays intact
    // because Object.assign mutates the first object passed to it and returns the
    // same object.
    const node = Object.assign(getNodeOrCreateStub(row.id), row)

    // Remove unwanted properties.
    delete node.parentId
    delete node.childrenIds

    // Get parent or create parent stub if parent node not already existing
    const parent = getNodeOrCreateStub(row.parentId || ROOT)

    // Add current node as child to parent
    parent.children.push(node)
  }

  // Return children of root node
  return nodes[ROOT].children
}

请注意,此代码当前还在叶节点中创建空的children数组,这与上面的示例不同。但是我认为这使代码更简单,因为它不必处理叶节点,而不必创建树或以后读取它! (您不必做children && children.length检查孩子,您总是可以直接访问children。)

© www.soinside.com 2019 - 2024. All rights reserved.