JavaScript riduce l'errore di lancio per più di due elementi

Sep 22 2020

Ho questo array:

const arr = [
  { someProp: [{ amount: 10 }]},
  { someProp: [{ amount: 12 }]},
];

e poi questo ridurre fn:

const sum = arr.reduce((prev, curr) => prev.someProp[0].amount + curr.someProp[0].amount);

Funziona se ci sono due elementi nell'array ma con tre genera:

Impossibile leggere la proprietà "0" di undefined "

Risposte

2 Ifaruki Sep 22 2020 at 13:06

In realtà è sufficiente restituire l'accumulatore + il nuovo valore.

0Immagino che tu voglia iniziare con, quindi devi aggiungere 0come secondo parametro

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);

Se lo vuoi più piccante qui con destrutturante

const arr =
    [
      { someProp: [{ amount: 10 }]},
      { someProp: [{ amount: 12 }]},
      { someProp: [{ amount: 12 }]},
    ];
    
const sum = arr.reduce((acc, { someProp: [{ amount }] }) => amount + acc, 0);

console.log(sum);

2 CristianTraìna Sep 22 2020 at 13:06

Seguendo la risposta di @Pointy, ecco come puoi farlo funzionare con un numero qualsiasi di elementi:

const sum = arr.reduce((prev, curr) => prev + curr.someProp[0].amount, 0);

prevè sempre l'elemento restituito in precedenza, quindi puoi tranquillamente usarlo come numero (e dato che lo stai solo sommando, puoi usarlo 0 come predefinito, quindi la prima volta che reduceviene invocato il valore di prevsarà 0)

2 Pointy Sep 22 2020 at 13:00

Stai restituendo un numero. Il valore di prevè sempre il precedente valore restituito dal callback, non l'elemento precedente. Quindi alla terza iterazione stai cercando di usare quel numero come se fosse un riferimento a un oggetto.

Aggiungi un secondo parametro (0) alla .reduce()chiamata e modifica la funzione da trattare prevcome il totale parziale (un numero semplice):

const sum = arr.reduce((prev, curr) => prev + curr.someProp[0].amount, 0);

Funziona così com'è quando ci sono due elementi perché senza quel secondo parametro, la prima iterazione vedrà l'elemento 0 come preve l'elemento 1 come curr. Quel comportamento funziona bene quando hai una matrice di numeri e vuoi solo eseguire un calcolo tra di loro, ma in questo caso hai bisogno di quel valore iniziale esplicitamente lì come secondo argomento.

PeterDarmis Sep 22 2020 at 13:39

Questa è una soluzione alternativa ... Utilizzando 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);