Digamos que tengo la siguiente matriz:
let arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]Me gustaría calcular la suma acumulativa de cada clave, pero también me gustaría que la salida fuera una matriz de la misma longitud con los valores acumulativos en cada paso. El resultado final debe ser:
[{a: 1, b: 2}, {a: 3, b: 6}, {a: 11, b: 5}]Mi problema es que no puedo obtener la matriz deseada. Solo obtengo el objeto final con esto:
let result = arr.reduce((accumulator, element) => { if(accumulator.length === 0) { accumulator = element } else { for(let i in element){ accumulator[i] = accumulator[i] + element[i] } } return accumulator }, []) console.log(result); // {a: 11, b: 5}Lo que busca suena como la función de orden superior scan() (tomando prestada la idea de ramda.js ), que le permite devolver un resultado acumulado para cada elemento dentro de su matriz. El método de escaneo es similar a cómo se comporta el método .reduce() , excepto que devuelve el acumulador para cada elemento. Puede construir la función scan() usted mismo así:
let arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}]; const scan = ([x, ...xs], fn) => xs.reduce((acc, elem) => { return [...acc, fn(acc.at(-1), elem)]; }, xs.length ? [x] : []); const res = scan(arr, (x, y) => ({a: x.a+ya, b: x.b+yb})); console.log(res); Puede considerar mejoras adicionales, como proporcionar un valor inicial al método de escaneo (similar a cómo reduce acepta uno). Además, si necesita una mejor compatibilidad con el navegador, el método .at() actualmente tiene una compatibilidad limitada con el navegador, por lo que puede considerar crear su propia función at() :
const at = (arr, idx) => idx >= 0 ? arr[idx] : arr[arr.length + idx];Puede lograr fácilmente el resultado usando reduce como
let arr = [ { a: 1, b: 2 }, { a: 2, b: 4 }, { a: 8, b: -1 }, ]; const result = arr.reduce((acc, curr, i) => { if (i === 0) acc.push(curr); else { const last = acc[i - 1]; const newObj = {}; Object.keys(curr).forEach((k) => (newObj[k] = curr[k] + last[k])); acc.push(newObj); } return acc; }, []); console.log(result);Algo como esto:
const arr = [{a: 1, b: 2}, {a: 2, b: 4}, {a: 8, b: -1}] const result = arr.reduce((accumulator, element, index) => { if(accumulator.length === 0) { accumulator.push(element) } else { const sum = {}; for(let i in element) { sum[i] = element[i] + (accumulator[index - 1][i] || 0) } accumulator.push(sum) } return accumulator }, []) console.log(result); Otra opción es mantener el resultado de la suma usando un Map , ayuda si las claves en los elementos de la matriz no son siempre las mismas.
const arr = [{a: 1, b: 2}, {a: 2}, {a: 8, b: -1}]; const map = new Map(); const result = arr.map((element) => { const sum = {}; for (let i in element) { sum[i]= element[i] + (map.get(i) || 0); map.set(i, sum[i]); } return sum; }); console.log(result);