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

在TypeScript中从扁平对象数组构建树形数组的方法咨询

扁平数组嵌套父对象转树形结构解决方案

问题背景

现有一组扁平JSON数据,每个子项的父级信息嵌套在attivita对象的id字段中(顶级项的attivita为null),需要将其转换为以children字段关联的树形结构。原有针对简单parent_id字段的嵌套函数无法适配该结构,需调整实现逻辑。

原始扁平数据

{
  "response": [
    {"id": 2,"alias": "BOAZ01","descrizione": "ISTANZA DA VALUTARE","dataCreazione": "2022-12-21T09:01:09.972819","dataAggiornamento": "2022-12-21T09:01:09.972776","dataDisabilitazione": null,"abilitato": true,"attivita": null},
    {"id": 4,"alias": "BOAZ02","descrizione": "ISTANZA IN VALUTAZIONE","dataCreazione": "2022-12-21T09:01:58.87955","dataAggiornamento": "2022-12-21T09:01:58.879506","dataDisabilitazione": null,"abilitato": true,"attivita": {"id": 2,"alias": "BOAZ01","descrizione": "ISTANZA DA VALUTARE","dataCreazione": "2022-12-21T09:01:09.972819","dataAggiornamento": "2022-12-21T09:01:09.972776","dataDisabilitazione": null,"abilitato": true,"assegnazione": null,"operatoreCorrente": {"codiceFiscale": "YNDKPR83A07I282K","nome": "SUPERADMIN","cognome": "ZERODD","email": "superadmin@zerodd.it","dataCreazione": "2022-12-14T16:30:02.02323","dataAggiornamento": "2022-12-14T16:48:30.933103","abilitazioneEmail": true,"tipo": "SUPERPOTERI","hibernateLazyInitializer": {}}}},
    {"id": 5,"alias": "BOAZ03","descrizione": "ISTANZA VALUTATA","dataCreazione": "2022-12-21T09:02:14.445142","dataAggiornamento": "2022-12-21T09:02:14.4451","dataDisabilitazione": null,"abilitato": true,"attivita": {"id": 4,"alias": "BOAZ02","descrizione": "ISTANZA IN VALUTAZIONE","dataCreazione": "2022-12-21T09:01:58.87955","dataAggiornamento": "2022-12-21T09:01:58.879506","dataDisabilitazione": null,"abilitato": true,"assegnazione": null,"operatoreCorrente": {"codiceFiscale": "YNDKPR83A07I282K","nome": "SUPERADMIN","cognome": "ZERODD","email": "superadmin@zerodd.it","dataCreazione": "2022-12-14T16:30:02.02323","dataAggiornamento": "2022-12-14T16:48:30.933103","abilitazioneEmail": true,"tipo": "SUPERPOTERI","hibernateLazyInitializer": {}}}},
    {"id": 6,"alias": "BOAZ03.1","descrizione": "ISTANZA VALUTATA-AMMISSIBILE","dataCreazione": "2022-12-21T09:02:40.046325","dataAggiornamento": "2022-12-21T09:02:40.046285","dataDisabilitazione": null,"abilitato": true,"attivita": {"id": 5,"alias": "BOAZ03","descrizione": "ISTANZA VALUTATA","dataCreazione": "2022-12-21T09:02:14.445142","dataAggiornamento": "2022-12-21T09:02:14.4451","dataDisabilitazione": null,"abilitato": true,"assegnazione": null,"operatoreCorrente": {"codiceFiscale": "YNDKPR83A07I282K","nome": "SUPERADMIN","cognome": "ZERODD","email": "superadmin@zerodd.it","dataCreazione": "2022-12-14T16:30:02.02323","dataAggiornamento": "2022-12-14T16:48:30.933103","abilitazioneEmail": true,"tipo": "SUPERPOTERI","hibernateLazyInitializer": {}}}},
    {"id": 7,"alias": "BOAZ03.2","descrizione": "ISTANZA VALUTATA-INAMMISSIBILE","dataCreazione": "2022-12-21T09:02:54.895132","dataAggiornamento": "2022-12-21T09:02:54.8951","dataDisabilitazione": null,"abilitato": true,"attivita": {"id": 5,"alias": "BOAZ03","descrizione": "ISTANZA VALUTATA","dataCreazione": "2022-12-21T09:02:14.445142","dataAggiornamento": "2022-12-21T09:02:14.4451","dataDisabilitazione": null,"abilitato": true,"assegnazione": null,"operatoreCorrente": {"codiceFiscale": "YNDKPR83A07I282K","nome": "SUPERADMIN","cognome": "ZERODD","email": "superadmin@zerodd.it","dataCreazione": "2022-12-14T16:30:02.02323","dataAggiornamento": "2022-12-14T16:48:30.933103","abilitazioneEmail": true,"tipo": "SUPERPOTERI","hibernateLazyInitializer": {}}}}
  ]
}

目标树形结构

[
  {
    "id": 2,
    "alias": "BOAZ01",
    "descrizione": "ISTANZA DA VALUTARE",
    "dataCreazione": "2022-12-21T09:01:09.972819",
    "dataAggiornamento": "2022-12-21T09:01:09.972776",
    "dataDisabilitazione": null,
    "abilitato": true,
    "children": [
      {
        "id": 4,
        "alias": "BOAZ02",
        "descrizione": "ISTANZA IN VALUTAZIONE",
        "dataCreazione": "2022-12-21T09:01:58.87955",
        "dataAggiornamento": "2022-12-21T09:01:58.879506",
        "dataDisabilitazione": null,
        "abilitato": true,
        "children": [
          {
            "id": 5,
            "alias": "BOAZ03",
            "descrizione": "ISTANZA VALUTATA",
            "dataCreazione": "2022-12-21T09:02:14.445142",
            "dataAggiornamento": "2022-12-21T09:02:14.4451",
            "dataDisabilitazione": null,
            "abilitato": true,
            "children": [
              {
                "id": 6,
                "alias": "BOAZ03.1",
                "descrizione": "ISTANZA VALUTATA-AMMISSIBILE",
                "dataCreazione": "2022-12-21T09:02:40.046325",
                "dataAggiornamento": "2022-12-21T09:02:40.046285",
                "dataDisabilitazione": null,
                "abilitato": true
              },
              {
                "id": 7,
                "alias": "BOAZ03.2",
                "descrizione": "ISTANZA VALUTATA-INAMMISSIBILE",
                "dataCreazione": "2022-12-21T09:02:54.895132",
                "dataAggiornamento": "2022-12-21T09:02:54.8951",
                "dataDisabilitazione": null,
                "abilitato": true
              }
            ]
          }
        ]
      }
    ]
  }
]

原有适用代码(简单结构)

此代码仅适用于父级ID直接存储在parent_id字段的扁平数组:

const nest = (items, id = null, link = 'parent_id') =>
  items
    .filter(item => item[link] === id)
    .map(item => ({ ...item, children: nest(items, item.id) }));

// 测试数据
const comments = [
  { id: 1, parent_id: null },
  { id: 2, parent_id: 1 },
  { id: 3, parent_id: 1 },
  { id: 4, parent_id: 2 },
  { id: 5, parent_id: 4 }
];

console.log(nest(comments));

解决方案

方案1:预处理数据+复用原有函数

先将嵌套的父ID提取为独立字段,再使用原有嵌套逻辑:

const response = [/* 原始数据数组 */];

// 预处理:提取父ID,移除不需要的attivita字段
const processedItems = response.map(item => ({
  ...item,
  parent_id: item.attivita?.id || null,
  attivita: undefined
}));

// 复用原有嵌套函数,调整后移除临时的parent_id字段
const nest = (items, id = null, link = 'parent_id') =>
  items
    .filter(item => item[link] === id)
    .map(item => {
      const { parent_id, ...rest } = item;
      return { ...rest, children: nest(items, item.id) };
    });

const tree = nest(processedItems);
console.log(JSON.stringify(tree, null, 2));

方案2:直接修改嵌套函数适配当前结构

无需预处理,直接在函数内解析嵌套的父ID:

const response = [/* 原始数据数组 */];

const nest = (items, parentId = null) => {
  return items
    .filter(item => {
      // 解析当前项的父ID:attivita存在则取其id,否则为null
      const itemParentId = item.attivita?.id || null;
      return itemParentId === parentId;
    })
    .map(item => {
      // 移除attivita字段,添加children子树
      const { attivita, ...rest } = item;
      return {
        ...rest,
        children: nest(items, item.id)
      };
    });
};

const tree = nest(response);
console.log(JSON.stringify(tree, null, 2));

方案对比

  • 方案1:逻辑清晰,原有嵌套函数可复用,若后续数据结构变化,仅需调整预处理逻辑。
  • 方案2:更简洁,减少一次数据遍历,直接适配当前结构,适合固定数据格式的场景。

内容的提问来源于stack exchange,提问作者Danilo Giovannico

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 11:24:57