0

So there is array of objects of below format

let inputs = [
    {
      "id": "614344d9d9c21c0001e6af2e",
      "groupName": "Unassigned",
      "parentGroup": "null"
    },
    {
      "id": "614447da152f69c3c1d52f2e",
      "groupName": "P1",
      "parentGroup": "null"
    },
    {
      "id": "614447da152f69c3c1d52f38",
      "groupName": "K1",
      "parentGroup": "C1"
    },
    {
      "id": "614447da152f69c3c1d52f3e",
      "groupName": "A2",
      "parentGroup": "C2"
    },
    {
      "id": "614447da152f69c3c1d52f40",
      "groupName": "G1",
      "parentGroup": "P2"
    },
    {
      "id": "614447da152f69c3c1d52f46",
      "groupName": "F1",
      "parentGroup": "null"
    },
    {
      "id": "614447da152f69c3c1d52f30",
      "groupName": "P2",
      "parentGroup": "null"
    },
    {
      "id": "614447da152f69c3c1d52f36",
      "groupName": "C2",
      "parentGroup": "P1"
    },
    
    {
        "id": "614447da152f69c3c1d52f3c",
        "groupName": "A1",
        "parentGroup": "C2"
      },
      {
        "id": "614447da152f69c3c1d52f34",
        "groupName": "C1",
        "parentGroup": "P1"
      },
      {
        "id": "614447da152f69c3c1d52f32",
        "groupName": "P3",
        "parentGroup": "null"
      },
      {
        "id": "614447da152f69c3c1d52f3a",
        "groupName": "K2",
        "parentGroup": "C1"
      },
      {
        "id": "614447da152f69c3c1d52f42",
        "groupName": "GG1",
        "parentGroup": "G1"
      },
      {
        "id": "614447da152f69c3c1d52f44",
        "groupName": "GGG1",
        "parentGroup": "GG1"
      }
  ]

i am trying to create a tree structure of format

{name:'p1',children:[{name:'c1':children:[]}]}

so i sorted all the elements of given array considering element with parentGroup as "null" to be at the top of the array.

 let finalArr = [];
 inputs.sort((a,b)=> (a.parentGroup === "null") ? -1 : 1);

And for each element of the inputs array, i was iterating below logic

inputs.forEach(ele => {
            if(ele.parentGroup === "null"){
             let child= {name:ele.groupName,children:[]};
             finalArr.push(child);
            }else{
              finalArr.forEach(item => {
                this.findNode(item,ele);
              })
            }
          });

If the 'parentGroup' of element is "null", then create a leaf kind of obj and push the element to 'finalArr' array

Else, then iterate across all the elements of 'finalArr' over a recursion function

public findNode(ele, obj){
    if(ele.children.length === 0){
      if(ele.name === obj.parentGroup){
        let child = {name:obj.groupName, children:[]};
      ele.children.push(child);
      }
    }else{
      let j = ele.children.length-1;
      this.findNode(ele.children[j--],obj);
    }
  }

This recursion function will check the element has children or not, if no children, then compare the parentGroup of given obj, with name of element from 'FinalArr'. if so ,push the current obj to the children of the element of finalArr.

else, that is, when children has more elements, the same recursion will be triggered until depth of the element is reached.

With this i tought i would make a tree structure with given inputs array, but when a parent has more children, of same level, this logic fails, so the inputs array has 'c1' which is a child of 'p1', but nly the child 'c2' resides, not sure the what is that i missed.

enter image description here

2
  • 1
    please address only a single problem in this question. do you have a problem to get a tree data structure or to render the tree in html? Commented Sep 27, 2021 at 18:14
  • To get a tree like data structure Commented Sep 27, 2021 at 19:46

2 Answers 2

0

I think the issue is how finalArr is used to generate the html elements.

When doing console.log(finalArr) it looks like the code block below. So it seems to me like the code you have to build the structure of finalArr is working fine.

// console.log(finalArr)

[
  { "name": "P3", "children": [] },
  {
    "name": "P2",
    "children": [
      {
        "name": "G1",
        "children": [
          { "name": "GG1", "children": [
              { "name": "GGG1", "children": [] }
            ]
          }
        ]
      }
    ]
  },
  { "name": "F1", "children": [] },
  {
    "name": "P1",
    "children": [
      { "name": "C2", "children": [
          { "name": "A1", "children": [] }
        ]
      }
    ]
  },
  { "name": "Unassigned", "children": [] }
]

EDIT

As OP mentioned in the comment C1 was missing. I've introduced a root element that will have the finalArr as its children and changed the findNode to use a for loop instead of forEach. In this way we can also break when we find the node and not continue recursing.

As part of the initial sorting we will sort the inputs by parentGroup so we ensure that a childs parent is added in the tree structure before we try to find it with findNode.

I believe this produces the correct result:


inputs.sort((a, b) => (a.parentGroup === "null" ? -1 : 1));

// Sort by parentGroup
let root = inputs.pop();
let inputsDescending = [root];
let max = inputs.length * inputs.length;
let c = 0;
while (inputs.length > 0 && max > c) {
  const child = inputs.pop();
  const hasParentGroup = inputsDescending.find(
    (parent) => parent.groupName === child.parentGroup
  );
  if (hasParentGroup || child.parentGroup === "null") {
    inputsDescending.push(child);
  } else {
    inputs.unshift(child);
  }
}

let rootEle = { name: "root", children: [] };

inputsDescending.forEach((obj) => {
  if (obj.parentGroup === "null") {
    let child = { name: obj.groupName, children: [] };
    rootEle.children.push(child);
  } else {
    findNode(rootEle, obj);
  }
});

function findNode(ele, obj) {
  if (ele.name === obj.parentGroup) {
    let child = { name: obj.groupName, children: [] };
    ele.children.push(child);
    return true;
  } else {
    const c = ele.children.length;
    if (c > 0) {
      for (let i = 0; c > i; i++) {
        const found = findNode(ele.children[i], obj);
        if (found) break;
      }
    }
  }
}

const finalArr = rootEle.children;

Now finalArr looks like this:

[
  { "name": "Unassigned", "children": [] },
  {
    "name": "P1",
    "children": [
      {
        "name": "C1",
        "children": [
          { "name": "K1", "children": [] },
          { "name": "K2", "children": [] }
        ]
      },
      {
        "name": "C2",
        "children": [
          { "name": "A2", "children": [] },
          { "name": "A1", "children": [] }
        ]
      }
    ]
  },
  { "name": "F1", "children": [] },
  {
    "name": "P2",
    "children": [
      { "name": "G1", "children": [
          { "name": "GG1", "children": [] }
        ]
      }
    ]
  },
  { "name": "P3", "children": [] }
]
Sign up to request clarification or add additional context in comments.

9 Comments

Yes this finalArr is missing the child node under 'P1', if you notice the 'inputs' array, there is an element { "id": "614447da152f69c3c1d52f34", "groupName": "C1", "parentGroup": "P1" }, so with this in place , the 'P1' should have 'C1' just like how the 'C2' is present under P1
Hi @Lisa, I didn't realize that C1 was missing. I've added an EDIT section to the answer where I believe the code is now producing the correct result.
Hi @Jens Ravn Jensen, sincere thanks for the answer, but i notice the nested children 'C1' too has two children which are 'K1' and 'K2' .The same with 'C2', has 'A1' and 'A2', with this solution, i could get only 1 child
Hi again @Lisa, I missed that. It was because of the order of the inputs. When we try to findNode for A2 we haven't yet added its parent C2 to the tree structure. I've added a sort by parentGroup section so that the inputs will be order from ancestor to descendent before we call findNode.
Thanks again, @Jens Ravn Jensen, with the updated logic, the last object in the given 'inputs' array is being missed, here 'GGG1' is missing, so i added one dummy element let dummyEle = { "id": "614447da152f69c3c1d52f44", "groupName": "", "parentGroup": "" } result.body.push(dummyEle);, then proceed with the logic u shared, it worked, thanks again for the solution.
|
0

You could take a standard algorithm for getting a tree with given data

const
    getTree = (data, id, parent, root, fn = o => o) => {
      var t = {};
      data.forEach(o => ((t[o[parent]] ??= {}).children ??= []).push(Object.assign(t[o[id]] = t[o[id]] || {}, fn(o))));
      return t[root].children;
    },
    data = [{ id: "614344d9d9c21c0001e6af2e", groupName: "Unassigned", parentGroup: "null" }, { id: "614447da152f69c3c1d52f2e", groupName: "P1", parentGroup: "null" }, { id: "614447da152f69c3c1d52f38", groupName: "K1", parentGroup: "C1" }, { id: "614447da152f69c3c1d52f3e", groupName: "A2", parentGroup: "C2" }, { id: "614447da152f69c3c1d52f40", groupName: "G1", parentGroup: "P2" }, { id: "614447da152f69c3c1d52f46", groupName: "F1", parentGroup: "null" }, { id: "614447da152f69c3c1d52f30", groupName: "P2", parentGroup: "null" }, { id: "614447da152f69c3c1d52f36", groupName: "C2", parentGroup: "P1" }, { id: "614447da152f69c3c1d52f3c", groupName: "A1", parentGroup: "C2" }, { id: "614447da152f69c3c1d52f34", groupName: "C1", parentGroup: "P1" }, { id: "614447da152f69c3c1d52f32", groupName: "P3", parentGroup: "null" }, { id: "614447da152f69c3c1d52f3a", groupName: "K2", parentGroup: "C1" }, { id: "614447da152f69c3c1d52f42", groupName: "GG1", parentGroup: "G1" }, { id: "614447da152f69c3c1d52f44", groupName: "GGG1", parentGroup: "GG1" }],
    tree = getTree(data, 'groupName', 'parentGroup', null, ({ groupName: name }) => ({ name }));

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

1 Comment

Thanks for the quick solution, but i was trying to get a final array of format something like this [{name:'p1',children:[{name:'c1':children:[]}]},{name:'F1',children:[]},{name:'P3', children:[]}]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.