-1

I have an array such as

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
    }
];

And I am looking for a solution, which condenses that array in such a manner, that all objects with the same id and name get summed by their expenseAmount, so that it results in:

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

Could you please help? Thanks!

Saphire
  • 1,812
  • 1
  • 18
  • 34
  • 2
    Does this answer your question? [merge object & sum a single property javascript](https://stackoverflow.com/questions/40262445/merge-object-sum-a-single-property-javascript) – aerial Jan 31 '22 at 07:08
  • Does [this answer](https://stackoverflow.com/a/62940311/4110233) you question? – TheChetan Jan 31 '22 at 07:08

4 Answers4

3

Array.prototype.reduce is your friend for tasks like these.

Find a preexisting object with the same id and add to the expense amount, if you can't find it, make it yourself and add it to the output array.

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));
Samathingamajig
  • 11,839
  • 3
  • 12
  • 34
0

This is one possible solution:

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

Explanation

  • Use .reduce to iterate through the array & generate result as an object
  • If current element itm's id already exists in the aggregator fin,
  • then, add itm.expenseAmount to existing prop (key: itm.id)
  • else, create a new prop (key: itm.id)
  • Finally, use Object.values() to extract only the values from resultant object

Code Snippet

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());
jsN00b
  • 3,584
  • 2
  • 8
  • 21
0

First step

Use filter to group by id and name

Second step

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);
Ian
  • 1,198
  • 1
  • 5
  • 15
-1

If you don't have a problem using a library for this purpose, you can use 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>
Niveth Saran
  • 130
  • 2
  • 5
  • 1
    If you run your code, you can see that it outputs the sum of all `expenseAmount`s, not on a per-id basis. Can be fixed by `_.sumBy(data, 'expenseAmount')` – Samathingamajig Jan 31 '22 at 07:26