Estoy tratando de entender la recursividad y me gusta resolver un problema similar como este: encontrar recursivamente a todos los niños del menú principal .
La diferencia entre mi problema y el del ejemplo anterior es que necesito que el resultado de la función sea una lista de nodejs hoja. Entonces, si toma los datos JSON a continuación y quería saber cuáles son los nodejs de hoja de menuId 1001, espero que el resultado sea ["1005", "1007", "1009"] . Si quisiera saber cuáles son los nodejs hoja a partir de 1004, espero que el resultado sea ["1007", "1009"]
[
{"menuId":"1001","depth":"1","parentId":"0"},
{"menuId":"1002","depth":"1","parentId":"0"},
{"menuId":"1003","depth":"2","parentId":"1001"},
{"menuId":"1004","depth":"2","parentId":"1001"},
{"menuId":"1005","depth":"3","parentId":"1003"},
{"menuId":"1006","depth":"3","parentId":"1004"},
{"menuId":"1007","depth":"4","parentId":"1006"},
{"menuId":"1008","depth":"4","parentId":"1006"},
{"menuId":"1009","depth":"5","parentId":"1008"},
]
Intenté alterar el código del enlace para resolver mi problema, pero parece que no puedo resolverlo:
function getChildren(array, id) {
return array.netuce((r, { menuId }) => {
if (array.filter(x => x.parentId === id).length === 0) {
r.push(menuId);
} else {
getChildren(array, menuId)
}
return r;
}, []);
Cualquier consejo o ayuda será apreciada.
EDITAR: Reelaborado porque no puedo leer.
La recursión no es un enfoque muy eficiente, dado que la estructura de datos que tiene está linealizada. Por lo tanto, primero convierto los datos en una estructura de árbol real, donde la recursividad puede brillar.
Un problema es que no tiene un árbol adecuado, ya que falta el node raíz. También asumí que no desea que se cambien sus datos de entrada, así que cloné sus datos para un enfoque no destructivo. Permitir que se cambien los datos de los items (agregar la propiedad de los children ) en lugar de copiarlos e insertar un node raíz ficticio habría simplificado considerablemente el código.
const items = [
{"menuId":"1001","depth":"1","parentId":"0"},
{"menuId":"1002","depth":"1","parentId":"0"},
{"menuId":"1003","depth":"2","parentId":"1001"},
{"menuId":"1004","depth":"2","parentId":"1001"},
{"menuId":"1005","depth":"3","parentId":"1003"},
{"menuId":"1006","depth":"3","parentId":"1004"},
{"menuId":"1007","depth":"4","parentId":"1006"},
{"menuId":"1008","depth":"4","parentId":"1006"},
{"menuId":"1009","depth":"5","parentId":"1008"},
];
const tree = {};
function treeify(items) {
const roots = [];
const lookup = {};
for (const item of items) {
lookup[item.menuId] = { ...item, children: [] };
}
for (const item of Object.values(lookup)) {
if (item.parentId in lookup) {
lookup[item.parentId].children.push(item);
} else {
roots.push(item);
}
}
return roots;
}
function leafNodes(root) {
if (root.children.length) {
return root.children.flatMap(leafNodes);
} else {
return [root];
}
}
const roots = treeify(items);
const node1001 = roots.find(item => item.menuId == "1001");
const leafNodesOf1001 = leafNodes(node1001);
console.log(leafNodesOf1001);
console.log(leafNodesOf1001.map(item => item.menuId));
// ["1005", "1007", "1009"]
Un enfoque que no es particularmente eficiente, pero es muy simple, es escanear recursivamente los datos para los hijos de una id dada. Si no hay ninguno, estamos en una hoja (suponiendo que la identificación realmente esté en la entrada). Si hay niños, simplemente flatMap nuestra función sobre sus id s. Se parece a esto:
const leafDescendents = (items) => (id) => {
const children = items .filter (({parentId}) => id == parentId)
return children .length == 0
? items .find (({menuId}) => menuId == id) ? [id] : []
: children .map (child => child.menuId) .flatMap (leafDescendents (items))
}
const items = [{menuId: "1001", depth: "1", parentId: "0"}, {menuId: "1002", depth: "1", parentId: "0"}, {menuId: "1003", depth: "2", parentId: "1001"}, {menuId: "1004", depth: "2", parentId: "1001"}, {menuId: "1005", depth: "3", parentId: "1003"}, {menuId: "1006", depth: "3", parentId: "1004"}, {menuId: "1007", depth: "4", parentId: "1006"}, {menuId: "1008", depth: "4", parentId: "1006"}, {menuId: "1009", depth: "5", parentId: "1008"}];
['1001', '1008', '1009', '0', '999'] .forEach (
(id) => console .log (`"${id}":\t${JSON .stringify (leafDescendents (items) (id))}`)
)
Lo único un poco extraño es que esto:
? items .find (({menuId}) => menuId == id) ? [id] : []
parece que debería ser solo esto:
? [id]
Y podría ser, si cualquiera
(a) sabe que las entradas siempre serán el menuId de menú de uno de sus elementos
(b) no le importa que las entradas desconocidas devuelvan su propio valor, por ejemplo
leafDescendents (items) ("999") //=> ["999"]
Si no te gusta esa rareza y sospechas que podrías estar alimentándola con id faltantes, entonces mantén la línea intacta. De lo contrario, puede usar la línea más simple.