Search code examples
javascriptnode.jsarraysnested-object

How to iteratively nest objects within an object


I have an array that looks like this:

const arr = [
{
  parent: 'A',
  children: ['B'],
},
{
  parent: 'B',
  children: ['C'],
},
{
  parent: 'C',
  children: ['D']
}];

and I want to create a function that will take this array and result in the following object:

const result = {
  parent: 'A',
  children: [{
    parent: 'B',
    children: [{
      parent: 'C',
      children: [{
        parent: 'D',
        children: []
      }]
    }]
  }]
};

so the result type would look like:

type Result = {
  parent: string;
  children: Result[];
};

What I've tried so far:

type TInput = {
  parent: string;
  children: string[];
};

type Result = {
  parent: string;
  children: Result[];
};

// can assume we know initial parent is 'A'
const fn = (parent: string, inputArr: TInput[]) => {
  const result: TResult[] = [];

  let newParent: string[] = [];
  while (newParent.length !== 0) {
    const index = inputArr.findIndex(
      (input) => input.parent === parent
    );
    result.push({
      parent: inputArr[index].parent,
      children: [], // need to populate on next pass?
    });
    newParent = inputArr[index].children;
  }
  return result;
};

I don't know how many objects will be in the input array, but can assume first object is known to be initial parent/child ('A' in the example). Any help much appreciated. Thanks


Solution

  • I'd use a parent map to recreate children attribute as arrays of parent objects:

    const arr = [
        {
          parent: 'A',
          children: ['B'],
        },
        {
          parent: 'B',
          children: ['C'],
        },
        {
          parent: 'C',
          children: ['D']
        },
        {
          parent: 'D',
          children: []
        }
      ];
    
    const makeTree = (manyParents,rootName) => {
        // copy parent objects into a map.
        let mapIt = new Map(manyParents.map(pObject => {
          return [pObject.parent, pObject];
        }));
        
        // recreate children arrays for each parents.
        mapIt.forEach((oneParent) => {
            let newChildrenArray = [];
            //find every children objects.
            oneParent.children.forEach((oneChild) => {
                newChildrenArray.push(mapIt.get(oneChild));
            });
            //replace children array.
            oneParent.children = newChildrenArray;
        });
        return mapIt.get(rootName);
    }
    
    let tree = makeTree(arr,'A');
    console.log(tree)