简体   繁体   English

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

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

I have a mock JSON like below:我有一个模拟 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
    }
]

and I need to convert it to below:我需要将其转换为以下内容:

[{
        "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
    }
]

The condition based on which we need to make changes is as follows: if corresponding to a particular id, if we have a parent_id then we need to add one property children in the individual object and put values as an array of matched parent_id object.我们需要进行更改的条件如下:如果对应于特定的id,如果我们有一个parent_id ,那么我们需要在单个对象中添加一个属性children ,并将值作为匹配的parent_id对象的数组。

I tried writing code for this and I came very close but I am unable to move forward.我尝试为此编写代码,我非常接近,但我无法继续前进。

Kindly suggest.请建议。

My code:我的代码:

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);

You can build the result tree by walking the array once and assigning nodes to an object that contains nodes by id, creating children arrays as necessary.您可以通过遍历数组一次并将节点分配给包含 id 节点的对象来构建结果树,并根据需要创建子数组。

After building the tree, assuming the data is well-formed and there is at least one node whose parent id does not exist in the tree (in your data array, there is no such id: "0" node), return that node's children.构建树后,假设数据格式正确并且树中至少有一个其父 id 不存在的节点(在您的数据数组中,没有这样的id: "0"节点),返回该节点的子节点. Sorting is only necessary if each level should be ordered in a particular way.仅当每个级别都应以特定方式排序时,才需要排序。

It's a bit more complicated if the data is not well formed;如果数据格式不正确,那就有点复杂了; in that case, the result should be the merged children of every node that references a nonexistent parent, but I'll omit this until motivation is present.在这种情况下,结果应该是引用不存在的父节点的每个节点的合并子节点,但我会省略它,直到出现动机。

Lastly, since the sort and reduce operations mutate the input, we can call .map(e => ({...e})) to create a copy and keep the function pure.最后,由于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);

this is a similar case like this one, but with jso items.这是一个类似的案例,但带有 jso 项目。
Javascript list loop/recursion to create an object Javascript列表循环/递归创建对象
items are assumed to be in good working order假定项目处于良好的工作状态

 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 )

"for the record" : I made the same code but placed inside an Array.prototype.reduce : “记录在案”:我编写了相同的代码,但放在了 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