Tenemos el siguiente tipo de objeto:
const obj = { a: { "=": 0 }, b: { c: { "=": 1 }, d: { e: { "=": 2 }, f: { g: { "=": 3 } } } } } Estoy tratando de escribir una función que devuelva una matriz con las claves de objeto, incluidas las anidadas, pero las agrupa si están anidadas y sus valores no son { "=": "something" } . Para explicarlo mejor, escribiré una salida de muestra deseada para el objeto anterior:
["a", "bc", "bde", "bdfg"] Todo lo que he logrado por ahora es una función que solo atraviesa el primer nivel, pero admito que me quedé atascado en la parte recursiva donde la misma función se aplicará en todos los niveles del objeto hasta que llegue a una entrada de tipo { "=": "something" } . Sigue mi código real:
function nestedObject(obj) { const operator = "=" const attributes = [] void (function traverse(obj) { if (isObject(obj)) { // <-- isObject(obj) just checks if typeof obj == "object", !Array.isArray(obj), obj !== null for (const [k,v] of Object.entries(obj)) { let attr = k for (const [k_,v_] of Object.entries(v)) { if (operator !== k_) { attr += "." + k_ // here is where the recursive part should start // but I didn't figure out yet how to make it right. // Of course calling traverse(v_) doesn't give the desired result. } attributes.push(attr) } } } })(obj) console.log(attributes) // <-- will output ["a", "bc", "bd"] }Espero haberme explicado lo suficientemente bien. Ni siquiera sé si esto es posible, pero creo que lo es. Me encantaría escuchar algunas ideas.
Tengo a mano algunas funciones de utilidad para facilitar la codificación. Uno de ellos toma un objeto y enumera todos los caminos de hojas en ese objeto, como una matriz de claves. Construir su función encima de eso se convierte simplemente en una cuestión de = las partes finales y unir los resultados con puntos:
const getPaths = (obj) => Object (obj) === obj ? Object .entries (obj) .flatMap (([k, v]) => getPaths (v) .map (p => [k, ...p])) : [[]] const nestedObject = (obj) => getPaths (obj) .map (p => p .at (-1) == '=' ? p .slice (0, -1): p) .map (p => p .join ('.')) const obj = {a: {"=": 0}, b: {c: {"=": 1}, d: {e: {"=": 2}, f: {g: {"=": 3}}}}} console .log (nestedObject (obj)) Esta es una versión un poco menos sofisticada de getPaths de lo que suelo escribir . Por lo general, distingo entre índices de matrices numéricas y claves de objetos de cadena, pero eso no es relevante aquí, por lo que esta versión está simplificada.
La función principal debe ser lo suficientemente clara además de eso.
Tenga en cuenta que esto no prohíbe las teclas = internas, por lo que si, paralelamente a g en su entrada, también tenía una h con una tecla = , así:
f: { g: { "=": 3 }, h: { "=": {i: { "=": 4}}} }daríamos este resultado:
["a", "bc", "bde", "bdfg", "bdfh=.i"] Si también desea eliminarlos, puede agregar esto entre las dos llamadas de map :
.filter (p => ! p.includes ('='))Aquí hay una pequeña función generadora que, dado un objeto, genera recursivamente pares como [ array-of-nested-keys, value ] :
function* enumRec(obj, keys=[]) { yield [keys, obj]; if (obj && typeof obj === 'object') for (let [k, v] of Object.entries(obj)) yield *enumRec(v, keys.concat(k)) } Para resolver el problema en cuestión, itere enumRec y recopile claves que terminen con a = :
for (let [keys, _] of enumRec(obj)) { if (keys.at(-1) === '=') console.log(keys.slice(0, -1).join('.')) }