Recorrer recursivamente un objeto para crear una lista de propiedades
Situación: Tengo un objeto grande que contiene múltiples subobjetos y subsubobjetos, con propiedades que contienen múltiples tipos de datos. Para nuestros propósitos, este objeto se parece a esto:
var object = {
aProperty: {
aSetting1: 1,
aSetting2: 2,
aSetting3: 3,
aSetting4: 4,
aSetting5: 5
},
bProperty: {
bSetting1: {
bPropertySubSetting : true
},
bSetting2: "bString"
},
cProperty: {
cSetting: "cString"
}
}
Necesito recorrer este objeto y crear una lista de claves que muestre la jerarquía, para que la lista termine luciendo así:
aProperty.aSetting1
aProperty.aSetting2
aProperty.aSetting3
aProperty.aSetting4
aProperty.aSetting5
bProperty.bSetting1.bPropertySubSetting
bProperty.bSetting2
cProperty.cSetting
Tengo esta función, que recorre el objeto y escupe las claves, pero no de forma jerárquica:
function iterate(obj) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property]);
}
else {
console.log(property + " " + obj[property]);
}
}
}
}
¿Alguien puede decirme cómo hacer esto? Aquí tienes un jsfiddle con el que puedes jugar: http://jsfiddle.net/tbynA/
Hice un VIOLÍN para ti. Estoy almacenando una stack
cadena y luego la envío, si la propiedad es de tipo primitivo:
function iterate(obj, stack) {
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property], stack + '.' + property);
} else {
console.log(property + " " + obj[property]);
$('#output').append($("<div/>").text(stack + '.' + property))
}
}
}
}
iterate(object, '')
Actualizar:17/01/2019
Solía haber una implementación diferente, pero no funcionó. Vea esta respuesta para una solución más bonita.
La solución de Artyom Neustroev no funciona en objetos complejos, así que aquí hay una solución funcional basada en su idea:
function propertiesToArray(obj) {
const isObject = val =>
val && typeof val === 'object' && !Array.isArray(val);
const addDelimiter = (a, b) =>
a ? `${a}.${b}` : b;
const paths = (obj = {}, head = '') => {
return Object.entries(obj)
.reduce((product, [key, value]) =>
{
let fullPath = addDelimiter(head, key)
return isObject(value) ?
product.concat(paths(value, fullPath))
: product.concat(fullPath)
}, []);
}
return paths(obj);
}
const foo = {foo: {bar: {baz: undefined}, fub: 'goz', bag: {zar: {zaz: null}, raz: 3}}}
const result = propertiesToArray(foo)
console.log(result)
EDITAR (23/05/2023):
Hay 4 soluciones diferentes (completas) con descripciones completas disponibles en LeetCode: https://leetcode.com/problems/array-of-objects-to-matrix/editorial/?utm_campaign=PostD19&utm_medium=Post&utm_source=Post&gio_link_id=EoZk0Zy9
Tendrás problemas con esto si el objeto tiene un bucle en su gráfico de objetos, por ejemplo, algo como:
var object = {
aProperty: {
aSetting1: 1
},
};
object.ref = object;
En ese caso, es posible que desee conservar las referencias de los objetos que ya ha recorrido y excluirlos de la iteración.
También puedes encontrarte con un problema si el gráfico de objetos es demasiado profundo, como:
var object = {
a: { b: { c: { ... }} }
};
Obtendrás un error de demasiadas llamadas recursivas. Ambos se pueden evitar:
function iterate(obj) {
var walked = [];
var stack = [{obj: obj, stack: ''}];
while(stack.length > 0)
{
var item = stack.pop();
var obj = item.obj;
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
var alreadyFound = false;
for(var i = 0; i < walked.length; i++)
{
if (walked[i] === obj[property])
{
alreadyFound = true;
break;
}
}
if (!alreadyFound)
{
walked.push(obj[property]);
stack.push({obj: obj[property], stack: item.stack + '.' + property});
}
}
else
{
console.log(item.stack + '.' + property + "=" + obj[property]);
}
}
}
}
}
iterate(object);
https://github.com/hughsk/flat
var flatten = require('flat')
flatten({
key1: {
keyA: 'valueI'
},
key2: {
keyB: 'valueII'
},
key3: { a: { b: { c: 2 } } }
})
// {
// 'key1.keyA': 'valueI',
// 'key2.keyB': 'valueII',
// 'key3.a.b.c': 2
// }
Simplemente haga un bucle para obtener los índices después.