1

I have been always using for to calculate any sum in a table, but I heard that there is a proper way, it is by using reduce, I followed the documentation and few examples using simple arrays, but I am using an array of objects, and here is my simple code, because I know I am missing something simple :

let dataRevenus = [
    { id: 1, label: intl.get("REVENUES_FONCIERS"), value: 230000000 },
    { id: 2, label: intl.get("REVENUES_VALUERS_MOBILIERES"), value: 25000000 },
    { id: 3, label: intl.get("PENSIONS_RETRAITES"), value: 33008.0 }
];

let test = 0;
let sum = dataRevenus
    ? dataRevenus.reduce((acc, item) => {
            console.log("here : " + parseFloat(item.value));

            test = test + parseFloat(item.value);

            return test;
      })
    : 0;

console.log(sum);

What I see in my console is that the first item has not been taken in consideration, this is what I get as a result :

here : 25000000
here : 33008
25033008

It seems like I am calcumating the sum correctly but the value of thje first item is not calculated

Any help would be much apppreciated

TaouBen
  • 1,165
  • 1
  • 15
  • 41
  • 1
    `parseFloat(item.value)` it's already a number, you don't need to parse it. – VLAZ Mar 01 '19 at 12:42
  • 2
    Possible duplicate of [Why does reduce not print the first value?](https://stackoverflow.com/questions/43479220/why-does-reduce-not-print-the-first-value) – Ivar Mar 01 '19 at 12:46
  • @VLAZ You are right, I dont need to but that is not the problem any way. – TaouBen Mar 01 '19 at 12:49
  • 3
    I know it isn't but it's still something I see many people get wrong. The real problem is the linked question - because you don't provide an initial value, `reduce` will take the first element as `acc` and thus it "skips" it because you don't get to process it as `item`. Another problem is that you aren't using `acc` but an outside variable. That *works* but it's not how `reduce` is supposed to run. – VLAZ Mar 01 '19 at 12:56

2 Answers2

3

you're using reduce incorrectly, try this, working on jsfiddle for it

let dataRevenus = [
    { id: 1, label: intl.get("REVENUES_FONCIERS"), value: 230000000 },
    { id: 2, label: intl.get("REVENUES_VALUERS_MOBILIERES"), value: 25000000 },
    { id: 3, label: intl.get("PENSIONS_RETRAITES"), value: 33008.0 }
];
let sum = dataRevenus
    ? dataRevenus.reduce((acc, item) => {
            console.log("here : " + parseFloat(item.value));
            return acc + item.value;
      }, 0)
    : 0;

console.log(sum);

I think the main thing missing is an initializer for accumulator. However as @VLAZ said you really shouldn't use the outside variable test the way you are.

https://jsfiddle.net/5uspgwL8/

updated to just add the initializer to your original code (and intl variable):https://jsfiddle.net/weomztad/

See the link @Ivar provided for more details.

BlackICE
  • 8,816
  • 3
  • 53
  • 91
2

The reduce method is an aggregate function that works with two arguments:

array.reduce(function(x, y), [initialValue])

The first is the custom function you supplied for aggregating data in the array (which has arguments itself), and the optional second one is an initial value. When you don't supply the function with an initial value (your case), the first time the function is called, the arguments of your function will be the first and second elements of your array. This means that, being item the second argument in your aggregate function, the expression you provided

test = test + parseFloat(item.value);

will start examining the second element of your array. Furthermore, being an aggregate function you don't need an external variable to hold the total value, because it will be automatically passed from an iteration to the next.

Davide Vitali
  • 1,017
  • 8
  • 24