0

I have data coming in that is in a linear format, e.g.:

const data = [
  {
    "id": "1",
    "parentId": null
  },
  {
    "id": "1.1",
    "parentId": "1"
  },
  {
    "id": "1.2",
    "parentId": "1"
  },
  {
    "id": "2",
    "parentId": null
  },
  {
    "id": "2.1",
    "parentId": "2"
  },
  {
    "id": "3",
    "parentId": null
  },
  {
    "id": "3.1",
    "parentId": "3"
  },
  {
    "id": "3.1.1",
    "parentId": "3.1"
  },
  {
    "id": "3.1.1.1",
    "parentId": "3.1.1"
  }
];

What I'm wanting to do is convert it to be in a hierarchical format, e.g.:

const hierarchicalData = [
  {
    "id": "1",
    "children": [
      {
        "id": "1.1",
      },
      {
        "id": "1.2",
      }
    ]
  },
  ...
]

I understand that there will need to be a level on recursion that can go on, but I get stuck at getting past the first level without having to brute force this thing knowing the number of levels beforehand.

I've been at this for roughly 3 hours now and can't quite grasp my head around how to do it.

This is an example demonstrating my issue:

var output = [];

$.each(data, function(index, value) {
    if (value.parentId === null) {
    value.children = [];
    output.push(value);
  } else {
    $.each(output, function(innerIndex, innerValue) {
        if (value.parentId === innerValue.id) {
        innerValue.children.push(value);
        return;
      }
    });
  }
});

console.log(output);
Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43
David
  • 5,877
  • 3
  • 23
  • 40
  • Please show your best try. Don't be shy. Rhyme – Roko C. Buljan Sep 20 '19 at 21:01
  • @RokoC.Buljan that would be the "this is an example demonstrating my issue" section. – David Sep 20 '19 at 21:19
  • lodash to the rescue: https://stackoverflow.com/a/45768527/1920035. Flatten was the keyword in finding the solution on SO. Thank you for all of your wonderful help @RokoC.Buljan I could not have done it with your inspirational wisdom. – David Sep 20 '19 at 21:44

1 Answers1

0

Here is an alternative approach using nothing but Vanilla JavaScript. The directly produced object o is not yet exactly what you wanted but a good starting point:

{
  "1": {
    "1": {
      "id": "1.1"
    },
    "2": {
      "id": "1.2"
    },
    "id": "1"
  },
  "2": {
    "1": {
      "id": "2.1"
    },
    "id": "2"
  },
  "3": {
    "1": {
      "1": {
        "1": {
          "id": "3.1.1.1"
        },
        "id": "3.1.1"
      },
      "id": "3.1"
    },
    "id": "3"
  }
}

Your exact result is then easily achievable by applying the recursive function mca() (=makeChildArray) to the object:

const data = [
  {"id": "1","parentId": null},
  {"id": "1.1","parentId": "1"},
  {"id": "1.2","parentId": "1"},
  {"id": "2","parentId": null},
  {"id": "2.1","parentId": "2"},
  {"id": "3","parentId": null},
  {"id": "3.1","parentId": "3"},
  {"id": "3.1.1","parentId": "3.1"},
  {"id": "3.1.1.1","parentId": "3.1.1"}
];

// the "one-liner" to make object o:
var o={};
data.forEach(el=>el.id.split('.').reduce((so,k)=>so[k]=so[k] || {id:el.id}, o));

function mca(co){
 if (typeof co==='object'){
  var ret={},cok=Object.keys(co);
  var ncok=cok.filter(k=>!isNaN(k));
  cok.filter(isNaN).forEach(k=>ret[k]=co[k]);
  if (ncok.length) ret.children=ncok.map(k=>mca(co[k]));
  return ret;
 }
 else return co;
}
console.log(mca(o).children);

The final result:

[
  {
    "id": "1",
    "children": [
      {
        "id": "1.1"
      },
      {
        "id": "1.2"
      }
    ]
  },
  {
    "id": "2",
    "children": [
      {
        "id": "2.1"
      }
    ]
  },
  {
    "id": "3",
    "children": [
      {
        "id": "3.1",
        "children": [
          {
            "id": "3.1.1",
            "children": [
              {
                "id": "3.1.1.1"
              }
            ]
          }
        ]
      }
    ]
  }
]
Carsten Massmann
  • 26,510
  • 2
  • 22
  • 43