Search code examples
javascriptarraysjavascript-objects

How to add new attribute that need to be calculated recursively in JavaScript


I want to dynamically add new attribute to all of the items in an array using map. But while adding it to each item, the value of this attribute is the sum of all previous items newly added attribute

Consider this example :

let persons = [{
"name": "A",
 "salary": 2
}, {
"name": "B",
 "salary": 5
},{
"name":"C",
"salary":12
}];

I want to return :

[{
    "name": "A",
     "salary": 2,
     "sumSalary":2
    }, {
    "name": "B",
     "salary": 5,
     "sumSalary":7
    },{
    "name":"C",
    "salary":12,
    "sumSalary":19
   }];

I've tried this one:

let mutatedPersons = persons.map((currentValue, index, mutatedPersons) => ({
  ...currentValue,
    sumSalary: currentValue.name === 'A' ? currentValue.salary : mutatedPersons[index - 1].sumSalary + currentValue.salary
}))

but i keep getting this :

[
  0: {name: "A", salary: 2, sumSalary: 2}
  1: {name: "B", salary: 5, sumSalary: NaN}
  2: {name: "C", salary: 12, sumSalary: NaN}
]

Solution

  • The mutatedPersons you refer to is the original array (see map's parameters), and not the updated array, which doesn't actually exist before the map end. You can cache the previous sum in an external variable (prevSumSalary), and use it as the basis of the new one:

    const persons = [{ name: "A", salary: 2 }, { name: "B", salary: 5 }, { name: "C", salary: 12 }]
    
    let prevSumSalary = 0;
    const mutatedPersons = persons.map((currentValue, index) => ({
      ...currentValue,
        sumSalary: (prevSumSalary = prevSumSalary + currentValue.salary)
    }))
    
    console.log(mutatedPersons);

    Another option is to use Array.reduce(), since you have access to the accumulated values:

    const persons = [{ name: "A", salary: 2 }, { name: "B", salary: 5 }, { name: "C", salary: 12 }]
    
    const mutatedPersons = persons.reduce((r, currentValue) => [...r, 
      ({
        ...currentValue,
          sumSalary: currentValue.salary + (r.length && r[r.length - 1].sumSalary)
      })
    ], [])
    
    console.log(mutatedPersons);