Estoy trabajando en una matriz de objetos que tienen atributos anidados. ¿Hay alguna forma de escribir una función recursiva para lograr el resultado mencionado a continuación?
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'], }, ], }, ];Cómo escribir una función en es6 de modo que se devuelva el siguiente resultado
[ { 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'] }, ];Se me ocurrió esta función recursiva. Los objetos de salida están en el orden previsto.
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.push(...child.childRows); }); // Adds child to group list. groups.push(groupWithChildren); groups.push(...directChildren); } } }); // Adds the new groups to the output array. finalArray.push(...groups) return finalArray; }Luego llamas a la función.
console.log(getNestedGroups(firstArray));Aquí está la salida.
[ { 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' ] } ] Editar: Gracias a J. Villasmil, vi que podemos optimizar array1 = array1.concat(array2) con array1.push(...array2) . Actualicé mi respuesta.
Encontré una solución. Intenté explicarte con comentarios en el código.
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))Función sin comentarios:
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 }Una buena forma de decir esto es que la propiedad childRows contiene cadenas u objetos, y la función childRowsIn devuelve las cadenas de childRows y childRowsIn los objetos de childRows.
function childRowsIn(object) { const childRows = (object.childRows || []).filter(e => ['string','object'].includes(typeof e)); return childRows.map(e => typeof e === 'string'? e: childRowsIn(e) ).flat() } const object = getData(); console.log(childRowsIn(object)) function getData() { 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'], }, ], }, ]; return { childRows: firstArray }; }