繁体   English   中英

将具有父 ID 的对象数组转换为嵌套树结构

[英]Convert array of objects with parent ids to a nested tree structure

我有一个模拟 JSON,如下所示:

const apiData = [{
        "id": 1,
        "label": "List item 1",
        "parent_id": 0
    },
    {
        "id": 5,
        "label": "List item 1",
        "parent_id": 1
    },
    {
        "id": 6,
        "label": "List item 1",
        "parent_id": 1
    },
    {
        "id": 7,
        "label": "List item 1",
        "parent_id": 1
    },
    {
        "id": 8,
        "label": "List item 1",
        "parent_id": 1
    },
    {
        "id": 9,
        "label": "List item 1",
        "parent_id": 8
    },
    {
        "id": 10,
        "label": "List item 1",
        "parent_id": 8
    },
    {
        "id": 2,
        "label": "List item 1",
        "parent_id": 0
    }
]

我需要将其转换为以下内容:

[{
        "id": 1,
        "label": "List item 1",
        "parent_id": 0,
        "children": [{
                "id": 5,
                "label": "List item 1",
                "parent_id": 1
            },
            {
                "id": 6,
                "label": "List item 1",
                "parent_id": 1
            },
            {
                "id": 7,
                "label": "List item 1",
                "parent_id": 1
            },
            {
                "id": 8,
                "label": "List item 1",
                "parent_id": 1,
                "children": [{
                        "id": 9,
                        "label": "List item 1",
                        "parent_id": 8
                    },
                    {
                        "id": 10,
                        "label": "List item 1",
                        "parent_id": 8
                    }
                ]
            }

        ]
    },
    {
        "id": 2,
        "label": "List item 1",
        "parent_id": 0
    }
]

我们需要进行更改的条件如下:如果对应于特定的id,如果我们有一个parent_id ,那么我们需要在单个对象中添加一个属性children ,并将值作为匹配的parent_id对象的数组。

我尝试为此编写代码,我非常接近,但我无法继续前进。

请建议。

我的代码:

const apiData = [
{'id': 1, 'label': 'List item 1', 'parent_id' : 0 },
{'id': 5, 'label': 'List item 1', 'parent_id' : 1 },
{'id': 6, 'label': 'List item 1', 'parent_id' : 1 },
{'id': 7, 'label': 'List item 1', 'parent_id' : 1 },
{'id': 8, 'label': 'List item 1', 'parent_id' : 1},
{'id': 9, 'label': 'List item 1', 'parent_id' : 8 },
{'id': 10, 'label': 'List item 1', 'parent_id' : 8 },
{'id': 2, 'label': 'List item 1', 'parent_id' : 0 },
];

function compare(a, b) {
  const idA = a.id;
  const idB = b.id;
  let comparison = 0;
  comparison = idA > idB ? 1 : (idA < idB ? -1 : 0);
  return comparison;
}

const sortedApiData = apiData.sort(compare);
const newSortedApiData = [...sortedApiData];
let a = []; 


for(let i = 0; i < sortedApiData.length ; i++){
  for(let j = 0 ; j < sortedApiData.length ; j++){
     if(i === j){
       continue;
     }
     else{
       if(sortedApiData[i].id === sortedApiData[j].parent_id){
         a.push(sortedApiData[j]);

       }
     }
  }

}

console.log(a);

您可以通过遍历数组一次并将节点分配给包含 id 节点的对象来构建结果树,并根据需要创建子数组。

构建树后,假设数据格式正确并且树中至少有一个其父 id 不存在的节点(在您的数据数组中,没有这样的id: "0"节点),返回该节点的子节点. 仅当每个级别都应以特定方式排序时,才需要排序。

如果数据格式不正确,那就有点复杂了; 在这种情况下,结果应该是引用不存在的父节点的每个节点的合并子节点,但我会省略它,直到出现动机。

最后,由于sortreduce操作会改变输入,我们可以调用.map(e => ({...e}))来创建副本并保持函数纯净。

 const unflatten = data => { const tree = data.map(e => ({...e})) .sort((a, b) => a.id - b.id) .reduce((a, e) => { a[e.id] = a[e.id] || e; a[e.parent_id] = a[e.parent_id] || {}; const parent = a[e.parent_id]; parent.children = parent.children || []; parent.children.push(e); return a; }, {}) ; return Object.values(tree) .find(e => e.id === undefined).children; }; const apiData = [{ "id": 1, "label": "List item 1", "parent_id": 0 }, { "id": 9, "label": "List item 1", "parent_id": 8 }, { "id": 8, "label": "List item 1", "parent_id": 1 }, { "id": 5, "label": "List item 1", "parent_id": 1 }, { "id": 6, "label": "List item 1", "parent_id": 1 }, { "id": 7, "label": "List item 1", "parent_id": 1 }, { "id": 10, "label": "List item 1", "parent_id": 8 }, { "id": 2, "label": "List item 1", "parent_id": 0 } ]; const expected = [{ "id": 1, "label": "List item 1", "parent_id": 0, "children": [{ "id": 5, "label": "List item 1", "parent_id": 1 }, { "id": 6, "label": "List item 1", "parent_id": 1 }, { "id": 7, "label": "List item 1", "parent_id": 1 }, { "id": 8, "label": "List item 1", "parent_id": 1, "children": [{ "id": 9, "label": "List item 1", "parent_id": 8 }, { "id": 10, "label": "List item 1", "parent_id": 8 } ] } ] }, { "id": 2, "label": "List item 1", "parent_id": 0 } ]; const unflattened = unflatten(apiData); console.log("Matches expected? " + (JSON.stringify(unflattened) === JSON.stringify(expected))); console.log(unflattened);

这是一个类似的案例,但带有 jso 项目。
Javascript列表循环/递归创建对象
假定项目处于良好的工作状态

 const apiData = [ { id: 1, label: 'List item 1', parent_id: 0 } , { id: 5, label: 'List item 1', parent_id: 1 } , { id: 6, label: 'List item 1', parent_id: 1 } , { id: 7, label: 'List item 1', parent_id: 1 } , { id: 8, label: 'List item 1', parent_id: 1 } , { id: 9, label: 'List item 1', parent_id: 8 } , { id: 10, label: 'List item 1', parent_id: 8 } , { id: 2, label: 'List item 1', parent_id: 0 } ]; const expected = [ { id: 1, label: 'List item 1', parent_id: 0, children: [ { id: 5, label: 'List item 1', parent_id: 1 } , { id: 6, label: 'List item 1', parent_id: 1 } , { id: 7, label: 'List item 1', parent_id: 1 } , { id: 8, label: 'List item 1', parent_id: 1, children: [ { id: 9, label: 'List item 1', parent_id: 8 } , { id: 10, label: 'List item 1', parent_id: 8 } ] } ] } , { id: 2, label: 'List item 1', parent_id: 0 } ]; let output = [] , pArr = [{arr:output,id:0}] ; for (let el of apiData) { let idx = pArr.findIndex(p=>p.id===el.parent_id); if(!Array.isArray(pArr[idx].arr)) { pArr[idx].arr = pArr[idx].arr.children = [] } pArr[idx].arr.push(nv = Object.assign({}, el) ) pArr[++idx] = { arr: nv, id:el.id } // possible parent } console.log ('output is expected ?', (JSON.stringify(output) === JSON.stringify(expected))) console.log( 'output', output )

“记录在案”:我编写了相同的代码,但放在了 Array.prototype.reduce 中:

let result = apiData.reduce((pArr,el,ix)=>
  {
  if (Number.isInteger(pArr))   // on ix===0
    { pArr = [{arr:[],id:0,ln:--pArr}]}

  let idx = pArr.findIndex(p=>p.id===el.parent_id);
  if(!Array.isArray(pArr[idx].arr))
    { pArr[idx].arr = pArr[idx].arr.children = [] }

  pArr[idx].arr.push(nv = Object.assign({}, el) )
  pArr[++idx] = { arr: nv, id:el.id }  // possible parent

  return (ix<pArr[0].ln) ? pArr : pArr[0].arr
  }
  , apiData.length ); 

// proof:
console.log ('result is expected ?', (JSON.stringify(result) === JSON.stringify(expected)))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM