根据对象级别的公共值减少数组

Reduce array based on common values on object level

我有一个数组,例如

let array = [
    {
        id: 1,
        name: "Name A",
        expenseAmount: 100
    },
    {
        id: 1,
        name: "Name A",
        expenseAmount: 50
    },
    {
        id: 3,
        name: "Name B",
        expenseAmount: 10
    },
    {
        id: 3,
        name: "Name B",
        expenseAmount: 20
    }
];

我正在寻找一种解决方案,它以这样一种方式压缩该数组,即所有具有相同 ID 和名称的对象都通过它们的费用金额求和,从而导致:

let array_goal = [
    {
        id: 1,
        name: "Name A",
        expenseAmount: 150
    },
    {
        id: 3,
        name: "Name B",
        expenseAmount: 30
    }
];

你能帮忙吗?谢谢!

Array.prototype.reduce 是您完成此类任务的朋友。

找一个已经存在的id相同的object加到expense amount中,找不到就自己做加到输出数组中。

let array = [{
    id: 1,
    name: "Name A",
    expenseAmount: 100
  },
  {
    id: 1,
    name: "Name A",
    expenseAmount: 50
  },
  {
    id: 3,
    name: "Name B",
    expenseAmount: 10
  },
  {
    id: 3,
    name: "Name B",
    expenseAmount: 20
  }
];

const condenseArray = (arr) => {
  return arr.reduce((out, {id, name, expenseAmount}) => {
    let data = out.find(({id: _id}) => _id === id);
    if (!data) {
      const newData = {id, name, expenseAmount: 0};
      out = [...out, newData];
      data = newData;
    }
    data.expenseAmount += expenseAmount;
    return out;
  }, []);
};

console.log(condenseArray(array));

如果为此目的使用库没有问题,您可以使用 lodash

// const _ = require('lodash') // use in source code if not using CDN

let array = [
    {
        id: 1,
        name: "Name A",
        expenseAmount: 100
    },
    {
        id: 1,
        name: "Name A",
        expenseAmount: 50
    },
    {
        id: 3,
        name: "Name B",
        expenseAmount: 10
    },
    {
        id: 3,
        name: "Name B",
        expenseAmount: 20
    }
];

const ans = _(array)
    .groupBy('name')
    .map((data, value) => ({
        id: data[0].id,
        name: data[0].name,
        expenseAmount: _.sumBy(data, 'expenseAmount')
    }))
    .value()

console.log(ans);
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js" integrity="sha256-qXBd/EfAdjOA2FGrGAG+b3YBn2tn5A6bhz+LSgYD96k=" crossorigin="anonymous"></script>

这是一种可能的解决方案:

const mergeIdSumExpenses = (arr = array) => (
  Object.values(arr.reduce(
    (fin, itm) => ({
        ...fin,
      [itm.id]: {
        ...itm,
        expenseAmount: (fin[itm.id]?.expenseAmount || 0) + itm.expenseAmount
      }
    }), {}
  ))
);

说明

  • 使用.reduce遍历数组并将结果作为对象生成
  • 如果当前元素 itmid 已经存在于聚合器中 fin,
  • 然后,将 itm.expenseAmount 添加到现有道具(键:itm.id
  • 否则,创建一个新道具(键:itm.id
  • 最后,使用 Object.values() 仅从结果对象中提取值

代码段

let array = [{
    id: 1,
    name: "Name A",
    expenseAmount: 100
  },
  {
    id: 1,
    name: "Name A",
    expenseAmount: 50
  },
  {
    id: 3,
    name: "Name B",
    expenseAmount: 10
  },
  {
    id: 3,
    name: "Name B",
    expenseAmount: 20
  }
];

const mergeIdSumExpenses = (arr = array) => (
    Object.values(arr.reduce(
    (fin, itm) => ({
        ...fin,
      [itm.id]: {
        ...itm,
        expenseAmount: (fin[itm.id]?.expenseAmount || 0) + itm.expenseAmount
      }
    }), {}
  ))
);

console.log(mergeIdSumExpenses());

第一步

Use filter to group by id and name

第二步

Use map, filter, reduce to calculate expenseAmount

const array = [
  {id:1,name:"Name A",expenseAmount:100},
  {id:1,name:"Name A",expenseAmount:50},
  {id:1,name:"Name B",expenseAmount:100},
  {id:3,name:"Name B",expenseAmount:10},
  {id:3,name:"Name B",expenseAmount:20}
];

const unique = array
  .filter((element, index, arr) => index === arr.findIndex(e => e.id == element.id && e.name == element.name))
  .map(u => {
    u.expenseAmount = 
      array
        .filter(a => a.id == u.id && a.name == u.name)
        .reduce((n, {expenseAmount}) => n + expenseAmount, 0);
    return u;
  });

console.log(unique);