无副作用的嵌套对象的总和值(减少)

Sum values of nested objects without side-effects (reduce)

我正在尝试计算嵌套在食物对象中的营养价值:

[
  {
    id: 'Potato',
    nutrition: [
      { id: 'PROT', val: 4 },
      { id: 'SUGAR', val: 1 }
    ]
  },
  {
    id: 'Banana',
    nutrition: [
      { id: 'FIB', val: 10 },
      { id: 'SUGAR', val: 4 }
    ]
  }
]

我使用 Array.prototype.reduce() 这样做:

foods.reduce((acc, { nutrition }) => {
    nutrition.map((x) => {
      let current = acc.find((y) => y.id === x.id)
      if (current) current.val += x.val
      else acc.push(x)
    })
  return acc
}, [])

这行得通,但它操纵了我的原始数组,我不明白为什么。我曾尝试使用传播运算符和 let/var 但无济于事。我怎样才能实现我想要的而没有副作用?

你可以利用 reduceforEach 最后取 Object.values,像这样:

const foods = [ { id: 'Potato', nutrition: [ { id: 'PROT', val: 4 }, { id: 'SUGAR', val: 1 } ] }, { id: 'Banana', nutrition: [ { id: 'FIB', val: 10 }, { id: 'SUGAR', val: 4 } ] }];

const result = Object.values(foods.reduce((a,{nutrition})=>{
    nutrition.forEach(({id, val})=>{
        (a[id] ??= {id, val:0}).val+=val;
    });
    return a;
},{}));

console.log(result);

您可以首先使用 forEach 而不是 map 因为在您的用例中不需要 map 到 return 一个新数组并修复上面的方法是在推送到 acc 数组时制作 x 的副本,如下所示:-

foods.reduce((acc, { nutrition }) => {
    nutrition.forEach((x) => {
      let current = acc.find((y) => y.id === x.id)
      if (current) current.val += x.val
      else acc.push({...x})
    })
  return acc
}, [])