Tengo una estructura de datos profundamente anidada y estoy interesado en hacer coincidir un cierto valor dentro de mi matriz (y una matriz de matrices) y luego insertar algunos datos dentro de una matriz adjunta. Por ejemplo, la siguiente es mi matriz de colores y está acompañada de una matriz moreColors que puede o no existir:
var myData = [{ "color": "green", "moreColors": [ { "color": "beige" }, { "color": "black", "moreColor": [ { "color": "grey" }, { "color": "white", "moreColors": [...] } ] } ] }] Estoy interesado en buscar en mi matriz el valor de color gris y en ese objeto agregar una matriz moreColors: [{"color" : "blue"}] . En ciertos casos, esto podría estar usando un método push() si la matriz ya existe. ¿Cómo lograría esto mejor? Mi objetivo aquí es que quiero agregar valores y actualizar/mutar la matriz myData aquí porque esto se pasará a otra función. El anidamiento aquí puede tener varios niveles de profundidad, por lo que un bucle simple dentro de un bucle no funcionará. ¿Funcionaría mejor aquí una función recursiva? También estoy abierto a mejores métodos o al uso de bibliotecas como guión bajo o lodash . Aunque preferiría una versión vanilla js. A continuación se muestra una solución recursiva que comencé, sin embargo, el código no se ejecutará a más de un nivel de profundidad.
findNested(myData, "grey") function findNested(myArray, color) { myArray.moreColors?.forEach(element => { if(element.color !== color){ if(element.moreColors.length > 0) { findNested(element.moreColors, color); } } else { element.moreColors.push({ "color": "blue" }); } }); }Aquí hay un ejemplo rápido de lo que creo que estás intentando.
findNestedColorObject() acepta una matriz y una cadena de color para buscar y devuelve el primer objeto cuya propiedad de color coincide.
updateMoreColors() acepta un objeto como lo devolvió el anterior y primero asigna moreColors si no existe, y luego lo empuja a la matriz.
function findNestedColorObject(array, color) { let colorObject; for (const obj of array) { if (obj.color === color) { colorObject = obj; } else if (obj.moreColors !== undefined) { colorObject = findNestedColorObject(obj.moreColors, color); } if (colorObject !== undefined) { break; } } return colorObject; } function updateMoreColors(colorObject, colors) { colorObject.moreColors ??= []; for (const color of [].concat(colors)) { colorObject.moreColors.push({ color }); } } const myData = [{ "color": "green", "moreColors": [{ "color": "beige" }, { "color": "black", "moreColors": [{ "color": "grey" }, { "color": "white", "moreColors": ["ochre"] }] }] }]; const greyObject = findNestedColorObject(myData, 'grey'); console.log('found:') console.log(greyObject); updateMoreColors(greyObject, 'purple'); console.log('updated:'); console.log(greyObject); const beigeObject = findNestedColorObject(myData, 'beige'); console.log('found:') console.log(beigeObject); updateMoreColors(beigeObject, ['salmon', 'crimson']); console.log('updated:'); console.log(beigeObject); // edit per the commments const data = [{ color: "beige", moreColors: [{ color: "blue" }] }, { color: "black", moreColors: [{ color: "white" }] }]; const blue = findNestedColorObject(data, 'blue'); console.log('fixed overwrite error:') console.log(blue);O, dado que su intento parece buscar y actualizar en la misma función, puede combinar las dos funciones anteriores. (Esto continuará actualizando todos los objetos que coincidan, no solo el primero).
function updateNestedColorObject(array, color, moreColors) { for (const obj of array) { if (obj.color === color) { obj.moreColors ??= []; for (const color of [].concat(moreColors)) { obj.moreColors.push({ color }); } } if (obj.moreColors !== undefined) { updateNestedColorObject(obj.moreColors, color, moreColors); } } } const myData = [{ "color": "green", "moreColors": [{ "color": "beige" }, { "color": "black", "moreColors": [{ "color": "grey" }, { "color": "white", "moreColors": ["ochre"] }] }] }]; updateNestedColorObject(myData, 'grey', 'purple'); updateNestedColorObject(myData, 'purple', 'beige'); updateNestedColorObject(myData, 'beige', ['salmon', 'crimson']); console.log(myData); Como se señaló en los comentarios, mi primer findNestedColorObject no estaba saliendo del ciclo como debería en una búsqueda exitosa. Se aplicó una solución rápida, aunque probablemente haya una solución más limpia.
Lo siento, hay profundidades a las que no me dejaré hundir. No te ayudaré a hacer algo tan bárbaro como mutar tus datos originales.
Pero si está interesado en una versión que cree una nueva estructura a partir de la anterior, con los nodos de color adicionales en su lugar adecuado, podemos escribir una recursividad razonablemente simple:
const addColor = (target, newColor) => (xs) => xs .map (({color, moreColors = []}) => ({ color, ... (color == target ? {moreColors: addColor (target, newColor) (moreColors) .concat ({color: newColor})} : moreColors .length > 0 ? {moreColors: addColor (target, newColor) (moreColors)} : {} ) })) const myData = [{color: "green", moreColors: [{color: "beige"}, {color: "black", moreColors: [{color: "grey"}, {color: "white", moreColors: [{color: "..."}]}]}]}] console .log (addColor ('grey', 'blue') (myData)) // console .log (myData) // uncomment to see that the original has not been folded, spindled, or mutilated .as-console-wrapper {max-height: 100% !important; top: 0} Mapeamos sobre la matriz, manteniendo intacta la propiedad de color y luego manejando moreColors de una de tres maneras:
color coincide con nuestro color de destino, recurrimos al nodo moreColors y le agregamos nuestro color adicional. (Si faltaba este nodo, lo hemos predeterminado a una matriz vacía).moreColor existentes, recurrimos a ellasmoreColor por completo.Hola, verifique esta función que hice hace un momento, es muy corta, creo que es realmente buena, no sé qué es una "recursión", pero probé esto en una matriz muy anidada con objetos y esto también funciona con objetos, creo que mire la salida :) EDITAR: ENCONTRÉ UNA MANERA MEJOR QUE NO ELIMINA LOS DATOS PERO DEVUELVE UN OBJ/OR ARRAY ORDENADO (puede pasar a esta función para ordenar) por favor envíe sus comentarios
var myData = [{ "color": "green", "moreColors": [ { "color": "blue" }, { "color": "blue", "moreColor": [ { "color": "blue" }, { "color": "blue", "moreColors": [] } ] } ] },['blue'],"blue"] function searchArrOrObj(objOrArray,color,newColor) { let arrayOrObj = Object.assign((objOrArray.constructor===Array?[]:{}), objOrArray) for (item in arrayOrObj) { if (arrayOrObj[item]===color) { arrayOrObj[item] = newColor; } else if (typeof arrayOrObj[item]==='object') { arrayOrObj[item] = searchArrOrObj(arrayOrObj[item],color,newColor) } } return arrayOrObj; } let newData = searchArrOrObj(myData,"blue","red") console.log(myData) console.log(newData)