如何转换嵌套对象数组结构并按指定顺序排序(使用reduce或其他方法)
如何转换嵌套对象数组结构并按指定顺序排序(使用reduce或其他方法)
我完全懂你的需求——把这组带关联关系的TourStation对象,转换成纯Station的嵌套层级结构,还要严格按照order字段排序对吧?用reduce就能完美解决,下面给你详细的实现思路和代码:
实现思路
核心是先建立一个节点映射表来快速定位父节点,然后通过reduce遍历原始数据构建嵌套关系,最后统一对每一层的节点按order排序,确保结构和顺序都符合预期。
完整代码实现
const DATA = [ { id: 47, tourId: 37, stationId: 7, parentStationId: null, order: 0, station: { id: 7, textCode: "1234", published: true, subjectId: 2, created: "2022-07-12T19:01:17.049Z", updated: "2022-07-15T11:36:46.195Z", expired: null, children: [] } }, { id: 50, tourId: 37, stationId: 9, parentStationId: null, order: 1, station: { id: 9, textCode: "asdd", published: true, subjectId: 2, created: "2022-07-15T13:47:55.557Z", updated: "2022-08-10T14:32:35.528Z", expired: null, children: [] } }, { id: 51, tourId: 37, stationId: 10, parentStationId: 9, order: 0, station: { id: 10, textCode: "123", published: true, subjectId: 2, created: "2022-07-25T11:49:21.688Z", updated: "2022-07-25T11:50:25.445Z", expired: null, children: [] } }, { id: 48, tourId: 37, stationId: 11, parentStationId: 9, order: 1, station: { id: 11, textCode: "sada", published: true, subjectId: 2, created: "2022-07-25T11:50:46.021Z", updated: "2022-07-25T11:50:48.567Z", expired: null, children: [] } }, { id: 49, tourId: 37, stationId: 12, parentStationId: 11, order: 0, station: { id: 12, textCode: "ASD", published: true, subjectId: 2, created: "2022-08-10T11:07:38.790Z", updated: "2023-01-20T12:44:59.925Z", expired: null } } ]; const dataExpected = [ { id: 7, textCode: "1234", published: true, subjectId: 2, created: "2022-07-12T19:01:17.049Z", updated: "2022-07-15T11:36:46.195Z", expired: null, children: [] }, { id: 9, textCode: "asdd", published: true, subjectId: 2, created: "2022-07-15T13:47:55.557Z", updated: "2022-08-10T14:32:35.528Z", expired: null, children: [ { id: 10, textCode: "123", published: true, subjectId: 2, created: "2022-07-25T11:49:21.688Z", updated: "2022-07-25T11:50:25.445Z", expired: null, children: [] }, { id: 11, textCode: "sada", published: true, subjectId: 2, created: "2022-07-25T11:50:46.021Z", updated: "2022-07-25T11:50:48.567Z", expired: null, children: [ { id: 12, textCode: "ASD", published: true, subjectId: 2, created: "2022-08-10T11:07:38.790Z", updated: "2023-01-20T12:44:59.925Z", expired: null } ] } ] } ]; const dataToReturn = DATA.reduce((acc, curr) => { // 提取当前Station数据,确保children数组存在(避免空值问题) const stationNode = { ...curr.station, children: curr.station.children || [] }; // 将当前节点存入映射表,方便后续快速查找父节点 acc.nodeMap[curr.stationId] = { node: stationNode, order: curr.order, parentId: curr.parentStationId }; // 处理根节点(无父节点的Station) if (curr.parentStationId === null) { acc.rootNodes.push({ node: stationNode, order: curr.order }); } else { // 处理子节点:找到父节点并将当前节点加入children列表 const parentNodeEntry = acc.nodeMap[curr.parentStationId]; if (parentNodeEntry) { parentNodeEntry.node.children.push({ node: stationNode, order: curr.order }); } } return acc; }, { // 初始化累加器:节点映射表 + 根节点临时列表 nodeMap: {}, rootNodes: [] }) // 第一步:对根节点按order升序排序 .rootNodes.sort((a, b) => a.order - b.order) // 第二步:递归处理每一层子节点的排序,并清理临时字段 .map(rootEntry => { const sortChildNodes = (nodeEntry) => { // 对子节点按order排序,再递归处理孙子节点 const sortedChildren = nodeEntry.node.children .sort((a, b) => a.order - b.order) .map(childEntry => { const sortedChild = sortChildNodes(childEntry); delete sortedChild.order; // 移除临时存储的order字段 return sortedChild; }); // 更新当前节点的children为排序后的结果 nodeEntry.node.children = sortedChildren; delete nodeEntry.order; // 移除临时字段 return nodeEntry.node; }; return sortChildNodes(rootEntry); }); console.log("RETURNED: ", JSON.stringify(dataToReturn, null, 2)); console.log("EXPECTED: ", JSON.stringify(dataExpected, null, 2));
代码解释
- 映射表
nodeMap:把每个Station的ID作为键,存储对应的节点、排序字段order和父节点ID,这样找父节点时不用反复遍历数组,效率更高。 reduce遍历构建结构:遍历每个TourStation,判断是根节点还是子节点,分别加入根节点列表或对应父节点的children数组。- 排序处理:先对根节点按
order升序排序,再用递归方式处理每一层子节点的排序,同时清理我们临时添加的order字段,确保最终输出结构和你给出的dataExpected完全一致。
如果你觉得递归有点繁琐,也可以用迭代的方式处理子节点排序,但递归在这里逻辑更清晰,适合这种层级不深的场景。
备注:内容来源于stack exchange,提问作者SlothOverlord
相关产品推荐
相关产品推荐

