Home > Software design >  Create an array of objects from array of objects which has nested fields JavaScript/es6
Create an array of objects from array of objects which has nested fields JavaScript/es6

Time:03-28

I am working on an array of objects which has nested attributes, Is there any way to write a recursive function to achieve below output mentioned

const firstArray = [
  {
    groupId: '1',
    childRows: [
      {
        groupId: '1a',
        childRows: ['abc', 'def'],
      },
      {
        groupId: '1b',
        childRows: ['pqr', 'xyz'],
      },
    ],
  },
  {
    groupId: '2',
    childRows: [
      {
        groupId: '2a',
        childRows: ['abz', 'dxy'],
      },
      {
        groupId: '2b',
        childRows: ['egh', 'mno'],
      },
    ],
  },
];

How to write a function in es6 such that below output is returned

[
  { groupId: '1', childRows: ['abc', 'def', 'pqr', 'xyz'] },
  { groupId: '1a', childRows: ['abc', 'def'] },
  { groupId: '1b', childRows: ['pqr', 'xyz'] },
  { groupId: '2', childRows: ['abz', 'dxy', 'egh', 'mno'] },
  { groupId: '2a', childRows: ['abz', 'dxy'] },
  { groupId: '2b', childRows: ['egh', 'mno'] },
];

CodePudding user response:

I came up with this recursive function. The output objects are in the intended order.

const getNestedGroups = (array, groups = []) => {
  const finalArray = [];

  // Group list should be empty as it is filled here.
  groups.length = 0;

  array.forEach((group) => {
    if (group.childRows.length > 0) {
      // If the group does not have nested groups we just append it to the group list.
      if (typeof group.childRows[0] === "string") {
        groups.push(group);
      }
      // If the group has children, the same function is called for them.
      else {
        // Call function for child
        const directChildren = [];
        const childGroups = getNestedGroups(group.childRows, directChildren);

        // Makes an object from the direct children (which were also made from their direct children if they had some).
        let groupWithChildren = { groupId: group.groupId, childRows: [] };
        childGroups.forEach((child) => {
          groupWithChildren.childRows = groupWithChildren.childRows.concat(child.childRows);
        });

        // Adds child to group list.
        groups.push(groupWithChildren);
        groups = groups.concat(directChildren);
      }
    }
  });

  return finalArray.concat(groups);
}

You then call the function.

console.log(getNestedGroups(firstArray));

Here is the output.

[
  { groupId: '1', childRows: [ 'abc', 'def', 'pqr', 'xyz' ] },
  { groupId: '1a', childRows: [ 'abc', 'def' ] },
  { groupId: '1b', childRows: [ 'pqr', 'xyz' ] },
  { groupId: '2', childRows: [ 'abz', 'dxy', 'egh', 'mno' ] },
  { groupId: '2a', childRows: [ 'abz', 'dxy' ] },
  { groupId: '2b', childRows: [ 'egh', 'mno' ] }
]

CodePudding user response:

I found a solution. I tried to explain you with comments in the code

const firstArray = [
    {
      groupId: '1',
      childRows: [
        {groupId: '1a',childRows: ['abc', 'def']},
        {groupId: '1b',childRows: ['pqr', 'xyz']}
      ]
    },
    {
      groupId: '2',
      childRows: [
        {groupId: '2a',childRows: ['abz', 'dxy']},
        { groupId: '2b',childRows: ['egh', 'mno']}
      ]
    },
];

function solution (arr){
  const result = [] 

  for (let i = 0; i < arr.length ; i  ) {
  
      let parent = [] // this is where I will accumulate all the "childRows" of the same parent
      
      let oldResultLengt = result.length // remember this for now
      
      for (let j = 0; j < arr[i].childRows.length; j  ) {
      
          const _childRows = arr[i].childRows[j].childRows // save the specific child array 
          
          result.push({'groupId':arr[i].childRows[j].groupId, 'childRows': _childRows}) // put the object into result array
          
          parent.push(..._childRows) // add to parent array

      }
      /* in this part of the code, at the first iteration the let result looks this:
      [
        {"groupId": "1a", "childRows": ["abc", "def"]},
        {"groupId": "1b", "childRows": ["pqr", "xyz"]}
      ]
      
    but oldResultLength is still 0, so I use splice to insert the parent element before their own childrens
 */
     result.splice(oldResultLengt, 0, {'groupId' : arr[i].groupId, 'childRows': parent})
  }
  return result
}

console.log(solution(firstArray))

Function without comments:

function solution (arr){
  const result = []
  for (let i = 0; i < arr.length ; i  ) {
      let parent = []
      let oldResultLengt = result.length
      for (let j = 0; j < arr[i].childRows.length; j  ) {
          const _childRows = arr[i].childRows[j].childRows
          result.push({'groupId':arr[i].childRows[j].groupId, 'childRows': _childRows})
          parent.push(..._childRows)
      }
     result.splice(oldResultLengt, 0, {'groupId' : arr[i].groupId, 'childRows': parent})
  }
  return result
}

  • Related