Home > front end >  How to iteratively nest objects within an object
How to iteratively nest objects within an object

Time:11-15

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

CodePudding user response:

If I get you right, one way you can go is recursive function. Read inline comments:

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

// Alphabet
const alphabet = 'abcdefghijklmnopqrstuvwxyz'.toUpperCase().split('');

// Recursive function
const rf = (arr, i = 0) => {
  // Result object
  let result = [];
  // Loop through array of objects
  for(const obj of arr) {
    // If parent or children equals current letter
    if(obj.parent === alphabet[i] || obj.children[0] === alphabet[i]) {
      // Form object in array
      result = [{
        parent: alphabet[i],
        children: rf(arr, i 1) // Go recursive with letter 1
      }];
    }
  }
  // Return result
  return result;
}

// Test
console.log(rf(arr)[0]);

CodePudding user response:

This seems to do the job :

This is the ts version :

// here i just copy your data
const data = [{
    parent: 'A',
    children: ['B'],
  },
  {
    parent: 'C',
    children: ['D']
  },
  {
    parent: 'B',
    children: ['C'],
  }
];

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

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

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


// there is the function that takes an input (the parent element) and an array (all the children)
const parseArray = (obj: TInput, arr: TInput[]): TResult => {
  return {
    parent: obj.parent,
    // if the children exists on the array, we use it, else we create an empty one, which will be used to recusivly generate the tree
    children: obj.children.map(child => data.find(e => e.parent === child) ?? {
      parent: child,
      children: []
    }).map(e => parseArray(e, arr))
  }
}

// we get the root obj (as you said the first el)
const root = data.shift()!

// and we call the function
console.log(parseArray(root, data))

// we verify that the objects are the same using json (directly using == on objects compares their locations on the disk)
console.log(JSON.stringify(parseArray(root, data)) === JSON.stringify(expectedResult))

And this is the snipped (we can't run ts directly on snippets) :

// here i just copy your data
const data = [{
    parent: 'A',
    children: ['B'],
  },
  {
    parent: 'C',
    children: ['D']
  },
  {
    parent: 'B',
    children: ['C'],
  }
];

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

// there is the function that takes an input (the parent element) and an array (all the children)
const parseArray = (obj, arr) => {
  return {
    parent: obj.parent,
    // if the children exists on the array, we use it, else we create an empty one, which will be used to recusivly generate the tree
    children: obj.children.map(child => data.find(e => e.parent === child) ?? {
      parent: child,
      children: []
    }).map(e => parseArray(e, arr))
  }
}

// we get the root obj (as you said the first el)
const root = data.shift()

// and we call the function
console.log(parseArray(root, data))

// we verify that the objects are the same using json (directly using == on objects compares their locations on the disk)
console.log(JSON.stringify(parseArray(root, data)) === JSON.stringify(expectedResult))

  • Related