You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何转换嵌套对象数组结构并按指定顺序排序(使用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));

代码解释

  1. 映射表nodeMap:把每个Station的ID作为键,存储对应的节点、排序字段order和父节点ID,这样找父节点时不用反复遍历数组,效率更高。
  2. reduce遍历构建结构:遍历每个TourStation,判断是根节点还是子节点,分别加入根节点列表或对应父节点的children数组。
  3. 排序处理:先对根节点按order升序排序,再用递归方式处理每一层子节点的排序,同时清理我们临时添加的order字段,确保最终输出结构和你给出的dataExpected完全一致。

如果你觉得递归有点繁琐,也可以用迭代的方式处理子节点排序,但递归在这里逻辑更清晰,适合这种层级不深的场景。

备注:内容来源于stack exchange,提问作者SlothOverlord

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.23 14:52:34