Tengo dos matrices: la primera arr: tiene una estructura de varios niveles.
segunda matriz - matriz lineal con objetos.
En mi función de actualización, repito, lanzo mi primera matriz de niños y, si la condición es verdadera, inserto los objetos en los atributos.
En producción, tengo arr2.length - 150000 objetos y arr1.length - múltiples niveles profundos.
¿Cómo puedo optimizar mi función para hacer un bucle más rápido con un gran volumen de datos? Ahora, espero unos 5 minutos en la iteración.
var arr1 = [{ "item_id": 2, "item_name": "test", "children": [{ "item_id": 39646, "item_name": "test1", "children": [{ "item_id": 35648, "item_name": "test2", "children": [{ "item_id": 35771, "item_name": "test3", "children": [], "attributes": [] }], }] }] }] var arr2 = [ { "item_id": 35771, "attr_value": "test", }, { "item_id": 35771, "attr_value": "test1", } ] const update = (array, id, object) => array.forEach(o => o.item_id === id ? o.attributes.push(object) : update(o.children, id, object) ); for (let item of arr2) { update(arr1, item.item_id, item); } console.log(arr1)Podemos recorrer el árbol una vez, después de convertir su segunda matriz a este formato:
{ 35771: ['test', 'test1'] // ... }y para cada nodo del árbol simplemente agregando los atributos de esta lista si existen. Aquí hay una implementación:
const updateForest = (atts) => (forest) => forest .map (({item_id, children = [], ...rest}) => ({ item_id, ...rest, children: updateForest (atts) (children), ...(atts [item_id] ? {attributes: atts [item_id]} : {}) })) const addAttributes = (forest, atts) => updateForest (atts .reduce ( (a, {item_id, attr_value}) => ((a [item_id] = a [item_id] || []), (a [item_id] .push (attr_value)), a), {} )) (forest) const arr1 = [{item_id: 2, item_name: "test", children: [{item_id: 39646, item_name: "test1", children: [{item_id: 35648, item_name: "test2", children: [{item_id: 35771, item_name: "test3", children: [], attributes: []}]}]}]}] const arr2 = [{item_id: 35771, attr_value: "test"}, {item_id: 35771, attr_value: "test1"}] console .log (addAttributes (arr1, arr2)) .as-console-wrapper {max-height: 100% !important; top: 0} updateForest recibe los atributos reformateados como se describe y devuelve una función que toma la estructura de su bosque (no es un árbol, porque no tiene necesariamente una sola raíz) y visita sus nodos, agregando atributos, si existen, recurrentes en la lista de elementos secundarios.
Nuestra función pública es addAttributes . Esto usa reduce para hacer esa conversión de formato en sus atributos, pasándolo y luego el bosque a updateForest .
Es importante notar que esto no muta sus estructuras originales, sino que crea otras nuevas. Considero que este es un objetivo importante al codificar. Pero si sus datos son tan grandes que no caben dos copias en la memoria, entonces tendríamos que omitir este enfoque.
Una forma sería crear un mapa que le diga exactamente dónde encontrar el elemento en arr1.
Algo como esto:
const mappedArr1 = { 2: {}, // Reference to item 2 39646: {}, // Reference to item 39646 35648: {}, // Reference to item 35648 35771: {}, // Reference to item 35771 }Y cuando actualices solo haz:
const item = mappedArr1[id]; item.attributes.push(object);Para crear el mapa tal vez use algo como esto:
const map = array => { const data = {}; const doMap = array => array.forEach(i => { data[i.item_id] = i; if (i.children && i.children.length > 0) { doMap(i.children); } }); doMap(array); return data; } const mappeArr1 = map(arr1);Aquí está el código completo:
var arr1 = [{ "item_id": 2, "item_name": "test", "children": [{ "item_id": 39646, "item_name": "test1", "children": [{ "item_id": 35648, "item_name": "test2", "children": [{ "item_id": 35771, "item_name": "test3", "children": [], "attributes": [] }], }] }] }] var arr2 = [ { "item_id": 35771, "attr_value": "test", }, { "item_id": 35771, "attr_value": "test1", } ] const map = array => { const data = {}; const doMap = array => array.forEach(i => { data[i.item_id] = i; if (i.children && i.children.length > 0) { doMap(i.children); } }); doMap(array); return data; } const mappedArr1 = map(arr1); for (let i of arr2) { const item = mappedArr1[i.item_id]; item.attributes.push(i.attr_value); } console.log(arr1)Use JSBench para probar el rendimiento de múltiples implementaciones, necesitará una muestra de datos más grande: https://jsbench.me