admin管理员组

文章数量:1405554

I have a mock JSON like below:

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.

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 pare(a, b) {
  const idA = a.id;
  const idB = b.id;
  let parison = 0;
  parison = idA > idB ? 1 : (idA < idB ? -1 : 0);
  return parison;
}

const sortedApiData = apiData.sort(pare);
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);

I have a mock JSON like below:

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.

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 pare(a, b) {
  const idA = a.id;
  const idB = b.id;
  let parison = 0;
  parison = idA > idB ? 1 : (idA < idB ? -1 : 0);
  return parison;
}

const sortedApiData = apiData.sort(pare);
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);

Share Improve this question edited Jan 17, 2020 at 3:54 ggorlen 57.9k8 gold badges114 silver badges157 bronze badges asked Jan 17, 2020 at 0:15 Kabeer SinghKabeer Singh 1432 silver badges7 bronze badges 3
  • 1 Just FYI, JSON is a term used to refer to strings. Once JSON has been parsed into an in-memory data structure, it's just a plain old JS object. The desired result you want here is an n-ary tree. – ggorlen Commented Jan 17, 2020 at 1:00
  • did you see my new answer below ? – Mister Jojo Commented Jan 17, 2020 at 13:05
  • Yeah i saw your answer and i accepted it. Thanks a lot for this beautiful code. – Kabeer Singh Commented Jan 17, 2020 at 15:56
Add a ment  | 

2 Answers 2

Reset to default 5

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.

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. Sorting is only necessary if each level should be ordered in a particular way.

It's a bit more plicated 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.

const unflatten = data => {
  const tree = data.map(e => ({...e}))
    .sort((a, b) => a.id - b.id)
    .reduce((a, e) => {
      a[e.id] ??= e;
      a[e.parent_id] ??= {};
      const parent = a[e.parent_id];
      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.
Javascript list loop/recursion to create an object
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 :

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

本文标签: javascriptConvert array of objects with parent ids to a nested tree structureStack Overflow