Estoy tratando de escribir una función recursiva que verificará cada objeto anidado en busca de un número par y devolverá una suma final de esos números. Estoy luchando para depurar la función que tengo hasta ahora.
function nestedEvenSum(obj, sum = 0) { for(const k in obj) { if (obj[k].constructor === Object) { return sum += nestedEvenSum(obj[k], sum); } if (typeof obj[k] === "number" && obj[k] % 2 === 0) { sum += obj[k]; } } return sum; } const obj = { a: 2, c: {c: {c: 2}, cc: 'b', ccc: 5}, e: {e: {e: 2}, ee: 'car'} } console.log(nestedEvenSum(obj)); La función devuelve 8 . Debería volver 6 .
Además, noté que se olvida completamente del objeto e , el último objeto llamado recursivamente es {c: 2} .
Esto exhibe un antipatrón de recursión clásico: pasar el resultado ( sum ) por la pila de llamadas como un parámetro al mismo tiempo que intenta pasarlo como resultado, lo que lleva a una situación confusa y una doble contabilidad.
Aquí hay una regla general fundamental para la recursividad: las dependencias de datos (las cosas que se usan para calcular un resultado) son los parámetros, los resultados son valores devueltos.
Haga una sum local para el marco, luego acumule en él durante el marco, ya sea porque cada elemento es un número (nodo de hoja en la búsqueda del árbol) o es un elemento secundario que debe explorarse recursivamente. No return inmediatamente al bucle o perderá a algunos de los niños.
function nestedEvenSum(obj) { let sum = 0; for (const k in obj) { if (obj[k].constructor === Object) { sum += nestedEvenSum(obj[k]); } else if (typeof obj[k] === "number" && obj[k] % 2 === 0) { sum += obj[k]; } } return sum; } const obj = { a: 2, c: { c: { c: 2 }, cc: 'b', ccc: 5 }, e: { e: { e: 2 }, ee: 'car' } }; console.log(nestedEvenSum(obj));Tenga en cuenta que este algoritmo ignora las matrices.
También tenga en cuenta que el diseño de la función es muy rígido debido al predicado % 2 === 0 . Puede considerar usar una función que atraviese cualquier estructura anidada y devuelva una matriz o un generador de resultados que luego se puedan filtrar, o una función que permita que un predicado de devolución de llamada arbitrario realice el filtrado.
Una excepción a la regla del flujo de datos unidireccional es que a veces querrá acumular resultados en una matriz de parámetros como una optimización en lugar de devolver y fusionar varias matrices a medida que retrocede en la pila de llamadas, pero eso no se aplica aquí. .
Debe eliminar la primera declaración de devolución.
Para obtener un código más corto, puede usar declaraciones condicionales.
Este enfoque mantiene la suma del objeto real y no entrega la suma al nivel anidado.
El traspaso solo es necesario para la optimización de llamadas de cola (TCO) debido a que se reemplaza la función anterior con la función recursiva de la pila. El TCO real está en Javascript y no es ampliamente compatible...
function nestedEvenSum(obj) { let sum = 0; for (const k in obj) { sum += obj[k] && typeof obj[k] === 'object' ? nestedEvenSum(obj[k]) : obj[k] % 2 === 0 ? obj[k] : 0; } return sum; } const obj = { a: 2, c: { c: { c: 2 }, cc: 'b', ccc: 5 }, e: { e: { e: 2 }, ee: 'car' } }; console.log(nestedEvenSum(obj));Creo que lo descubrí.
Primero, regresas si encuentras un objeto, lo que significa que te detendrás antes, así que eliminé el 'regreso' anticipado.
En segundo lugar, estás contando dos veces si encuentras un objeto, porque estás pasando la suma que ya tienes y luego la sumas a la suma que ya tienes.
Mira esto, solo un par de pequeños cambios:
function nestedEvenSum(obj, sum = 0) { for(const k in obj) { if (obj[k].constructor === Object) { sum = nestedEvenSum(obj[k], sum); } if (typeof obj[k] === "number" && obj[k] % 2 === 0) { sum += obj[k]; } } return sum; } const obj = { a: 2, c: {c: {c: 2}, cc: 'b', ccc: 5}, e: {e: {e: 2}, ee: 'car'} } console.log(nestedEvenSum(obj));