1

I'm starting out with a flat JSON input as such (simple example):

[
{id:1, value:'child1', parentId:2, sortOrder:1},
{id:2, value:'root1', parentId:null, sortOrder:1},
{id:3, value:'root2', parentId:null, sortOrder:2},
{id:4, value:'child2', parentId:1, sortOrder:2},
{id:5, value:'root3', parentId:null, sortOrder:3},
{id:6, value:'child1', parentId:2, sortOrder:1},
{id:7, value:'root4', parentId:null, sortOrder:4}
];

The input can be of arbitrary depth and length, and needs to reformatted to a collection of nested arrays based on the parent-child relationships, as well as sorted in ascending order at each nesting level.

Either native JS or UnderscoreJS can be used to format the output.

The output would be formatted as a json structure with a basic form:

root1 
  child1
  child2
root2
  child1
    child1
    child2
  child2

  etc...

Where each element is a JSON object.

The nesting depth can be anything since the data is most likely coming from a db table with the above flat structure.

Any thoughts?

  • [This answer](http://stackoverflow.com/a/17849353) gave me exactly what I needed to accomplish this. – melicent Jun 04 '15 at 22:24
  • Please learn what JSON is and what it is not. *Any thoughts?* Yes, my thoughts are that you need to write a "computer program" to do this. –  Aug 17 '16 at 05:22

2 Answers2

1

I would do this job as follows. I could have used the value properties to attach the nested objects but the question was unclear at that point. Instead i have created the children properties to construct the nested structure.

var flat = [
{id:1, value:'child1', parentId:2, sortOrder:1},
{id:2, value:'root1', parentId:null, sortOrder:1},
{id:3, value:'root2', parentId:null, sortOrder:2},
{id:4, value:'child2', parentId:1, sortOrder:2},
{id:5, value:'root3', parentId:null, sortOrder:3},
{id:6, value:'child1', parentId:2, sortOrder:1},
{id:7, value:'root4', parentId:null, sortOrder:4}
],
     lut = flat.sort((a,b) => a.sortOrder - b.sortOrder)
               .reduce((t,o) => { o.children === void 0 && (o.children = []);
                                  t[o.id] = t[o.id] === void 0 ? o : (o.children = t[o.id].children,o);
                                  o.parentId     !== null &&
                                  (t[o.parentId] !== void 0 ? t[o.parentId].children.push(o)
                                                            : t[o.parentId] = {id: o.parentId, children: [o]});
                                  return t;
                                },{}),
  nested = Object.keys(lut).reduce((a,k) => lut[k].parentId === null ? a.concat(lut[k]): a,[]);
console.log(nested);

Also the sort stage wouldn't be necessary if you would like to place the children objects in the parent's children array property way you receive them.

Redu
  • 25,060
  • 6
  • 56
  • 76
1

Our plan will be to move the children under the parent (into a new array-valued children property), and then filter them out.

const flat = [
{id:1, value:'child1', parentId:2, sortOrder:1},
{id:2, value:'root1', parentId:null, sortOrder:1},
{id:3, value:'root2', parentId:null, sortOrder:2},
{id:4, value:'child2', parentId:1, sortOrder:2},
{id:5, value:'root3', parentId:null, sortOrder:3},
{id:6, value:'child1', parentId:2, sortOrder:1},
{id:7, value:'root4', parentId:null, sortOrder:4}
];

const nested = flat.filter((elt, idx, arr) => {
  const parent = arr.find(e => e.id === elt.parentId);
  if (!parent) return true;
  (parent.children = parent.children || []).push(elt);
});

console.log(nested);

Sorting will be left as an exercise.