JavaScript reduce el error de lanzamiento para más de dos elementos
Tengo esta matriz:
const arr = [
{ someProp: [{ amount: 10 }]},
{ someProp: [{ amount: 12 }]},
];
y luego esto reduce fn:
const sum = arr.reduce((prev, curr) => prev.someProp[0].amount + curr.someProp[0].amount);
Funciona si hay dos elementos en la matriz pero con tres arroja:
No se puede leer la propiedad '0' de indefinido "
Respuestas
En realidad, solo necesita devolver el acumulador + el nuevo valor.
Quieres comenzar con, 0supongo, por lo que debes agregar 0como segundo parámetro
const arr =
[
{ someProp: [{ amount: 10 }]},
{ someProp: [{ amount: 12 }]},
{ someProp: [{ amount: 12 }]},
];
const sum = arr.reduce((acc, item) => item.someProp[0].amount + acc, 0);
console.log(sum);
Si lo quieres más picante aquí con desestructuración
const arr =
[
{ someProp: [{ amount: 10 }]},
{ someProp: [{ amount: 12 }]},
{ someProp: [{ amount: 12 }]},
];
const sum = arr.reduce((acc, { someProp: [{ amount }] }) => amount + acc, 0);
console.log(sum);
Siguiendo la respuesta de @Pointy, así es como puede hacer que funcione con cualquier cantidad de elementos:
const sum = arr.reduce((prev, curr) => prev + curr.someProp[0].amount, 0);
preves siempre el elemento devuelto anteriormente, por lo que puede usarlo de manera segura como un número (y dado que solo lo está sumando, puede usarlo 0 como predeterminado, por lo que la primera vez que reducese invoca el valor de prevserá 0)
Devuelve un número. El valor de preves siempre el valor de retorno anterior de la devolución de llamada, no el elemento anterior. Por lo tanto, en la tercera iteración, intenta usar ese número como si fuera una referencia de objeto.
Agregue un segundo parámetro (0) a la .reduce()llamada y cambie la función para tratarla prevcomo el total acumulado (un número simple):
const sum = arr.reduce((prev, curr) => prev + curr.someProp[0].amount, 0);
Funciona como está cuando hay dos elementos porque sin ese segundo parámetro, la primera iteración verá el elemento 0 como prevy el elemento 1 como curr. Ese comportamiento funciona bien cuando tiene una matriz de números y solo desea realizar un cálculo entre ellos, pero en este caso necesita ese valor inicial explícitamente allí como segundo argumento.
Esta es una solución alternativa ... Usando Array.filter().
const arr = [{
someProp: [{
amount: 10
}]
},
{
someProp: [{
amount: 12
}]
},
{
someProp: [{
amount: -231
}]
},
{
someProp: [{
amount: 21265
}]
},
{
someProp: [{
amount: 1239
}]
},
{
someProp: [{
amount: -6
}]
},
];
const sum = arr.filter((val, index) => {
if (index > 0) {
arr[index].someProp[0].amount = parseInt(val.someProp[0].amount) + parseInt(arr[index - 1].someProp[0].amount);
}
return index == arr.length - 1;
})[0].someProp[0].amount;
console.log(sum);