在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
相关产品推荐
相关产品推荐

