'Combine duplicate elements and sum the amount

I have an array object with incomes, for any duplicate incomes I want to have a single record which has a sum of all duplicates.

This the array object

const incomes = [
  {
    incomeType: 'DIVIDEND',
    incomeSubType: 'RECEIPT',
    payerName: 'Employer',
    expiryDate: '2022-03-10',
    regularAmountCalculated: {
      value: 2500,
      currencyCode: 'AUD'
    },
    irregularAmountCalculated: null,
    bonusCalculated: {
      value: 200,
      currencyCode: 'AUD'
    }
  },
  {
    incomeType: 'DIVIDEND',
    incomeSubType: 'RECEIPT',
    payerName: 'Employer',
    expiryDate: '2022-03-10',
    regularAmountCalculated: {
      value: 2500,
      currencyCode: 'AUD'
    },
    irregularAmountCalculated: null,
    bonusCalculated: {
      value: 200,
      currencyCode: 'AUD'
    }
  }
];

I am expecting the output to have a only on record for Dividend and calculated amount as 5000.

Expected output

const incomes = [
  {
    incomeType: 'DIVIDEND',
    incomeSubType: 'RECEIPT',
    payerName: 'Employer 1',
    expiryDate: '2022-03-10',
    regularAmountCalculated: {
      value: 5000,
      currencyCode: 'AUD'
    },
    irregularAmountCalculated: null,
    bonusCalculated: {
      value: 200,
      currencyCode: 'AUD'
    }
  },
];

I have written:

const totals:any = [];
statementOfIncomes.forEach(x => {
  const obj = totals.find(o => o.incomeType === 'DIVIDEND');
  if (obj) {
    obj.regularAmountCalculated.value = obj.regularAmountCalculated.value + x.regularAmountCalculated?.value;
  } else {
    totals.push(x);
  }
});

The error I get is

ERROR TypeError: Cannot assign to read only property 'value' of object '[object Object]'



Solution 1:[1]

I would suggest using a Map to store all unique incomes. You have to loop over your incomes, check if the map already has an entry based on the incomeType. If not, add it to the map, else get the existing value and add the regularAmount to it. Last you have to convert your map back to an Array. This has a runtime of O(2n) instead of O(n^2) as stated in your first approach.

const map = new Map();

incomes.forEach((income) => {
  if (!map.has(income.incomeType)) {
    map.set(income.incomeType, income);
  } else {
    const existingIncome = map.get(income.incomeType);

    existingIncome.regularAmountCalculated.value += income.regularAmountCalculated.value;

    map.set(income.incomeType, existingIncome);
  }
});

const uniqueIncomes = Array.from(map, ([_key, value]) => value);

// [
//   {
//     incomeType: 'DIVIDEND',
//     incomeSubType: 'RECEIPT',
//     payerName: 'Employer',
//     expiryDate: '2022-03-10',
//     regularAmountCalculated: { value: 5000, currencyCode: 'AUD' },
//     irregularAmountCalculated: null,
//     bonusCalculated: { value: 200, currencyCode: 'AUD' },
//   },
// ];

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 marcobiedermann