-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!

2

4 Answers 4

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

Sign up to request clarification or add additional context in comments.

Comments

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

Comments

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

Comments

-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/[email protected]/lodash.min.js" integrity="sha256-qXBd/EfAdjOA2FGrGAG+b3YBn2tn5A6bhz+LSgYD96k=" crossorigin="anonymous"></script>

1 Comment

If you run your code, you can see that it outputs the sum of all expenseAmounts, not on a per-id basis. Can be fixed by _.sumBy(data, 'expenseAmount')

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.