Как добавить новый атрибут, который нужно вычислять рекурсивно в JavaScript - PullRequest
0 голосов
/ 13 октября 2018

Я хочу динамически добавлять новый атрибут ко всем элементам в массиве, используя карту.Но при добавлении его к каждому элементу значение этого атрибута является суммой всех добавленных атрибутов всех предыдущих элементов

Рассмотрим этот пример:

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

Я хочу вернуть:

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

Я пробовал это:

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

, но я продолжаю получать это:

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

Ответы [ 4 ]

0 голосов
/ 13 октября 2018

Это идеальный случай для Array#reduce.

. Можно использовать аккумулятор (целое salarySum), чтобы получить прямой доступ к последнему salarySum значению.

Всякий раз, когда кто-то думает о агрегатной функции , он должен немедленно подумать о Array#reduce на первом месте!

Кроме того, я предоставил вам решение, которое не 'мутировать источник persons, но он создает новый массив с salarySum для каждого элемента:

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

const {
  persons: persons_,
  salarySum
} = persons.reduce((result, person) =>
  result.persons.push({
    ...person,
    salarySum: (result.salarySum += person.salary)
  }) && result, {
    salarySum: 0,
    persons: []
  })

console.log(persons_)
console.log(salarySum)
0 голосов
/ 13 октября 2018

Вы можете использовать замыкание над sum и использовать его для добавленного свойства sumSalary.

var data = [{ name: "A", salary: 2 }, { name: "B", salary: 5 }, { name: "C", salary: 12 }],
    result = data.map((sum => o => ({ ...o, sumSalary: sum += o.salary }))(0));
    
console.log(result);
0 голосов
/ 13 октября 2018

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

let sum = 0;
persons.map(curr => {
  sum += curr.salary;
  curr.sumSalary = sum;
});

console.log(persons);
0 голосов
/ 13 октября 2018

mutatedPersons, на который вы ссылаетесь, это исходный массив (см. параметры карты ), а не обновленный массив, который на самом деле не существует до конца карты.Вы можете кэшировать предыдущую сумму во внешней переменной (prevSumSalary) и использовать ее в качестве основы для новой:

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

Другой вариант - использовать Array.reduce(), поскольку у вас есть доступ к накопленным значениям:

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