Quiero crear una función recursiva que reciba una Lista de objetos que contenga el id y parent_id. Si el padre de un elemento está en la lista, quiero eliminarlo y agregarlo al padre.
Convierte esto:
{ "id": 180, "children": [], "parent_id": 195, "name": "Object 180" }, { "id": 193, "children": [], "parent_id": 180, "name": "Object 193" }, { "id": 194, "children": [], "parent_id": 180, "name": "Object 194" } { "id": 199, "children": [], "parent_id": 187, "name": "Object 199" } { "id": 304, "children": [], "parent_id": 193, "name": "Object 304" }A esto:
{ "id": 180, "children": [ { "id": 193, "children": [ { "id": 304, "children": [], "parent_id": 193, "name": "Object 304" } ], "parent_id": 180, "name": "Object 193" }, { "id": 194, "children": [], "parent_id": 180, "name": "Object 194" } ], "parent_id": 195, "name": "Object 180" }, { "id": 199, "children": [], "parent_id": 187, "name": "Object 199" }A veces, parent_id es nulo y no hay límite de niveles de los padres.
No necesitas una función recursiva. Simplemente haga un seguimiento de los elementos que ya ha visto y, si existe un padre, agréguelos a parent.children o agregue un nuevo nodo raíz.
Se adjunta un ejemplo de solución completa.
type Item = { id: number, children: Item[], parent_id: number, name: string, } const items: Item[] = [ { "id": 180, "children": [], "parent_id": 195, "name": "Object 180" }, { "id": 193, "children": [], "parent_id": 180, "name": "Object 193" }, { "id": 194, "children": [], "parent_id": 180, "name": "Object 194" }, { "id": 199, "children": [], "parent_id": 187, "name": "Object 199" }, { "id": 304, "children": [], "parent_id": 193, "name": "Object 304" } ]; function nest(items:Item[]): Item[] { const output: Item[] = []; const idToItem = new Map<number,Item>(); for (let item of items) { // Either add to parent. Or create a new root level node if (idToItem.has(item.parent_id)) { idToItem.get(item.parent_id)!.children.push(item); } else { idToItem.set(item.id, item); output.push(item); } } return output; } console.log(nest(items));Dado que la respuesta de basarat no tiene en cuenta los elementos anidados en más de un nivel.
Aquí una solución que crea una salida con profundidad de anidamiento arbitraria:
const listToTree = (input) => { const map = new Map(input.map((item) => [item.id, item])); const output = []; for (const item of input) { if (map.has(item.parent_id)) { map.get(item.parent_id).children.push(map.get(item.id)); } else { output.push(map.get(item.id)); } } return output; }; const input = [ { "id": 180, "value": 10, "children": [], "parent_id": 195, "name": "Object 180" }, { "id": 193, "value": 10, "children": [], "parent_id": 180, "name": "Object 193" }, { "id": 194, "value": 10, "children": [], "parent_id": 180, "name": "Object 194" }, { "id": 199, "children": [], "parent_id": 187, "name": "Object 199" }, { "id": 304, "value": 10, "children": [], "parent_id": 193, "name": "Object 304" }, { "id": 305, "value": 10, "children": [], "parent_id": 194, "name": "Object 304" } ]; const output = listToTree(input); console.log(output);Si desea agregar valores a lo largo de las cadenas de ascendencia del árbol resultante, le recomendaría hacerlo en una función separada después. Esto mantendrá su código más limpio, más fácil de probar y más legible.
La implementación depende de si su matriz de entrada está ordenada o no (hijos antes que padres). Si desea procesar entradas no ordenadas, debe recorrer cada cadena de ascendencia.
function aggregateValue(branch) { const children = branch.children || []; return children.reduce((sum, child) => sum + aggregateValue(child), branch.value || 0); } function aggregateValueAlongBranches(tree) { return tree.map((branch) => { return { ...branch, aggregatedValue: aggregateValue(branch), children: aggregateValueAlongBranches(branch.children), }; }); } const input = [ { "id": 180, "value": 10, "children": [ { "id": 193, "value": 10, "children": [ { "id": 304, "value": 10, "children": [], "parent_id": 193, "name": "Object 304" } ], "parent_id": 180, "name": "Object 193" }, { "id": 194, "value": 10, "children": [ { "id": 305, "value": 10, "children": [], "parent_id": 194, "name": "Object 304" } ], "parent_id": 180, "name": "Object 194" } ], "parent_id": 195, "name": "Object 180" }, { "id": 199, "children": [], "parent_id": 187, "name": "Object 199" } ]; const output = aggregateValueAlongBranches(input); console.log(output);