数组对象合并问题

原数据这样的数据结构
想要根据 mergeLayerParam 合并相同项
当存在 active 字段时候,active 那一项作为父级;否则第一个 mergeLayerParam 作为第一项

同一级可能存在多个不同的 mergeLayerParam,合并的数据放入父级的 mergeLayers 字段

// 原
[
  {
    "title": "1",
    "children": [
      {
        "title": "1-1",
        "children": [
          {
            "title": "1-1-1",
            "children": [
              {
                "title": "1-1-1-1",
                "mergeLayerParam": "bbb"
              },
              {
                "title": "1-1-1-2",
                "mergeLayerParam": "bbb"
              }
            ]
          },
          {
            "title": "1-1-2",
            "children": [
              {
                "title": "1-1-2-1"
              }
            ]
          },
          {
            "title": "1-1-3",
            "children": [
              {
                "title": "1-1-3-1"
              },
              {
                "title": "1-1-3-2"
              },
              {
                "title": "1-1-3-3"
              },
              {
                "title": "1-1-3-4"
              }
            ]
          },
          {
            "title": "1-1-4",
            "mergeLayerParam": "aaa"
          },
          {
            "title": "1-1-5",
            "mergeLayerParam": "aaa",
            "active": true
          },
          {
            "title": "1-1-6",
            "mergeLayerParam": "aaa",
          },
          {
            "title": "1-1-7",
            "mergeLayerParam": "你好"
          },
          {
            "title": "1-1-8",
            "mergeLayerParam": "你好"
          },
          {
            "title": "1-1-9",
            "mergeLayerParam": "你好",
          }
        ]
      },
      {
        "title": "1-2"
      },
      {
        "title": "1-3"
      }
    ]
  },
  {
    "title": "2"
  }
]
// 转换成
[
  {
    "title": "1",
    "children": [
      {
        "title": "1-1",
        "children": [
          {
            "title": "1-1-1",
            "children": [
              {
                "title": "1-1-1-1",
                "mergeLayerParam": "bbb",
                "mergeLayers": [
                  {
                    "title": "1-1-1-1",
                    "mergeLayerParam": "bbb",
                  },
                  {
                    "title": "1-1-1-2",
                    "mergeLayerParam": "bbb"
                  }
                ]
              }
            ]
          },
          {
            "title": "1-1-2",
            "children": [
              {
                "title": "1-1-2-1"
              }
            ]
          },
          {
            "title": "1-1-3",
            "children": [
              {
                "title": "1-1-3-1"
              },
              {
                "title": "1-1-3-2"
              },
              {
                "title": "1-1-3-3"
              },
              {
                "title": "1-1-3-4"
              }
            ]
          },
          {
            "title": "1-1-5",
            "mergeLayerParam": "aaa",
            "active": true,
            "mergeLayers": [
              {
                "title": "1-1-4",
                "mergeLayerParam": "aaa"
              },
              {
                "title": "1-1-5",
                "mergeLayerParam": "aaa",
                "active": true,
              },
              {
                "title": "1-1-6",
                "mergeLayerParam": "aaa",
              },
            ]
          },
          {
            "title": "1-1-7",
            "mergeLayerParam": "你好",
            "mergeLayers": [
              {
                "title": "1-1-7",
                "mergeLayerParam": "你好"
              },
              {
                "title": "1-1-8",
                "mergeLayerParam": "你好"
              },
              {
                "title": "1-1-9",
                "mergeLayerParam": "你好",
              }
            ]
          }
        ]
      },
      {
        "title": "1-2"
      },
      {
        "title": "1-3"
      }
    ]
  },
  {
    "title": "2"
  }
]
阅读 1.6k
2 个回答

思路就是遍历,对有 mergeLayerParam 进行分组处理。分组是使用映射表来临时保存的。默认使用第一个节点的副本来作为合并节点,如果遇到 active 的,就用 active 的那个节点属性替换它的属性。

function handle(parent) {
    if (Array.isArray(parent)) {
        // 这个分支只是用来处理根
        return handle({ children: parent }).children;
    }

    const { children } = parent;
    if (!children) { return parent; }
    const mergeMap = {};
    parent.children = children.reduce(
        (children, child) => {
            if (child.mergeLayerParam) {
                let active = mergeMap[child.mergeLayerParam];
                if (!active) {
                    active = { ...child };
                    mergeMap[child.mergeLayerParam] = active;
                    children.push(active);
                }
                if (child.active) {
                    const { mergeLayers } = active;
                    delete active.mergeLayers;
                    // 本来只需要 assign 即可,前面两句只是为了保证 margeLayers 是最后一个属性
                    Object.assign(active, child, { mergeLayers });
                }
                (active.mergeLayers ??= []).push(child);
            } else {
                children.push(child);
            }

            return children;
        },
        []
    );

    parent.children.forEach(handle);
    return parent;
}

const nodes = handle(data);
console.dir(nodes, { depth: null });
const mergeNodeByLayerParams = (root)=>{
    let checkItems = [root]
    const createTreeNode = (nodes)=>{
        nodes = [...nodes]
        const rootNode = nodes.shift()
        rootNode.mergeLayers = [...nodes]
        return rootNode
    }
    const getHandlerChildren = (checkItem)=>{
        let children = [...(checkItem.children || []), ...(checkItem.mergeLayers || [])]
        if(("mergeLayerParam" in checkItem)) {
            return children
        }
        const childrenSt = new Set(children)
        const mergeNodeMap = {}
        childrenSt.forEach(item=>{
            if(!("mergeLayerParam" in item)) return;
            if(!mergeNodeMap[item.mergeLayerParam]) {
                mergeNodeMap[item.mergeLayerParam] = []
            }
            if(item.active) {
                mergeNodeMap[item.mergeLayerParam].unshift(item)
            } else {
                mergeNodeMap[item.mergeLayerParam].push(item)
            }
        })
        let extraTree = []
        const mergeNodes = Object.values(mergeNodeMap)
        if(mergeNodes.length) {
            extraTree = mergeNodes.map(createTreeNode)
            mergeNodes.flat().forEach(item=>{
                childrenSt.delete(item)
            })
        }
        children = [...childrenSt,...extraTree]
        return children
    }
    while(checkItems.length) {
        const checkItem = checkItems.shift()
        const children = getHandlerChildren(checkItem)
        if(checkItem.children) {
            checkItem.children = children
        }
        checkItems = children.concat(checkItems)
    }
    return root
}

题目看着有点费劲。。你看看是不是这个

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题