Necesito ayuda con la implementación específica del primer algoritmo transversal de profundidad iterativa. Tengo un objeto como este (es solo un ejemplo, el objeto podría tener más propiedades y estar más anidado):
const root = { a: 1, b: { c: { d: { e: 2, f: 3, } }, g: [ { h: 4, i: 5, }, { j: 6, k: 7, } ] } }Lo que necesito es una función que atraviese todo el objeto y devuelva una matriz como esta:
[ {"a": 1}, {"bcde": 2}, {"bcdf": 3}, {"bg0.h": 4}, {"bg0.i": 5}, {"bg1.j": 6}, {"bg1.k": 7}, ]Logré crear un algoritmo que resuelve mi problema, pero al final necesita un paso adicional. El resultado del algoritmo es una matriz de cadenas como esa:
[ 'a^1', 'bcde^2', 'bcdf^3', 'bg0.h^4', 'bg0.i^5', 'bg1.j^6', 'bg1.k^7' ] entonces, para lograr lo que quiero, tengo que hacer una iteración completa sobre el resultado de mi algoritmo, dividir cadenas por el símbolo ^ y luego crear objetos basados en eso.
Esta es la parte con la que necesito ayuda: ¿cómo puedo mejorar/cambiar mi solución para no tener que hacer el último paso?
function dft(root) { let stack = []; let result = []; const isObject = value => typeof value === "object"; stack.push(root); while (stack.length > 0) { let node = stack.pop(); if (isObject(node)) { Object.entries(node).forEach(([childNodeKey, childNodeValue]) => { if (isObject(childNodeValue)) { const newObject = Object.fromEntries( Object.entries(childNodeValue).map(([cnk, cnv]) => { return [`${childNodeKey}.${cnk}`, cnv]; }) ); stack.push(newObject); } else { stack.push(`${childNodeKey}^${childNodeValue}`); } }) } else { result.push(node); } } return result.reverse(); }Puede enviar el par childNodeKey childNodeValue directamente como un objeto a su matriz de result .
Cambio
stack.push(`${childNodeKey}^${childNodeValue}`);a
const newEntry = {} newEntry[childNodeKey] = childNodeValue result.push(newEntry);o con sintaxis ES2015 (necesitaría un transpilador para compatibilidad con el navegador )
result.push({[childNodeKey]: childNodeValue});Función completa:
const root = { a: 1, b: { c: { d: { e: 2, f: 3, } }, g: [ { h: 4, i: 5, }, { j: 6, k: 7, } ] } } function dft(root) { let stack = []; let result = []; const isObject = value => typeof value === "object"; stack.push(root); while (stack.length > 0) { let node = stack.pop(); if (isObject(node)) { Object.entries(node).forEach(([childNodeKey, childNodeValue]) => { if (isObject(childNodeValue)) { const newObject = Object.fromEntries( Object.entries(childNodeValue).map(([cnk, cnv]) => { return [`${childNodeKey}.${cnk}`, cnv]; }) ); stack.unshift(newObject); } else { const newEntry = {} newEntry[childNodeKey] = childNodeValue result.push({[childNodeKey]: childNodeValue}); } }) } else { result.push(node); } } return result; } console.log(dft(root))Mantendría los pares <keys,value> en la pila y solo crearía una clave de cadena al almacenar un objeto recién creado:
function dft(obj) { let stack = [] let res = [] stack.push([[], obj]) while (stack.length) { let [keys, val] = stack.pop() if (!val || typeof val !== 'object') { res.push({ [keys.join('.')]: val }) } else { Object.entries(val).forEach(p => stack.push([ keys.concat(p[0]), p[1], ])) } } return res.reverse() } // const root = { a: 1, b: { c: { d: { e: 2, f: 3, } }, g: [ { h: 4, i: 5, }, { j: 6, k: 7, } ] } } console.log(dft(root))Como mencionaste, casi lo tienes completo. Simplemente haga que la entrada de la matriz sea un objeto justo antes de insertarlo en result . Al dividir Array.prototype.split('^') puede obtener 'bg0.h^4' >>> ['bg0.h', '4'] . Entonces, el resto es pan comido:
if (isObject(node)) { ... } else { const keyAndValue = node.split('^') // approach 1) // const key = keyAndValue[0] // const value = keyAndValue[1] // dynamic key setting // result.push({[key]: value}); // approach 2) // or in short, // dynamic key setting result.push({[keyAndValue[0]]: keyAndValue[1]}); }