How to obtain a sum of positive and negative values of various objects in an array based on a property of equal value?

Viewed 103

I would like help with a problem:

I have an array with several objects with two properties "Date" and "Amount"

The corresponding "Date" value is 1-12, they are months of the year.

The "Amount" value corresponds to the movement made. It will be positive if a value has been added, and it will be negative when a value is withdrawn.

"Ex:

var payments = [
{"amount": "123.00", "date": "01"},
{"amount": "123.00", "date": "01"},
{"amount": "-23.00", "date": "01"},
{"amount": "-23.00", "date": "01"},
{"amount": "23.00", "date": "01"},
{"amount": "123.00", "date": "02"},
{"amount": "123.00", "date": "02"},
{"amount": "-12.00", "date": "06"},
{"amount": "-10.00", "date": "06"},
{"amount": "-12.00", "date": "07"},
{"amount": "100.00", "date": "08"},
{"amount": "-100.00", "date": "08"},
];

I would like to take from this array the sum of all "amounts" that have the same "data" value, separating the negatives from the positives.

Ex:

In January[01], was added [123 + 123 + 23] = 269;
and has been withdrawn [- 23 - 23] = - 46;

In February[02] was added [123 + 123] = 246;
and no value was taken;

In August [08] was added [100];
and has been withdrawn [100];

I will use the data in an apex`s chart.

I believe that I could use several "IFs" for each month of the year, would that be it or could it be done in another way?

Thanks a lot for the help!

5 Answers

you can try:

txn={};

for(payment of payments) {
  var date=payment.date;
  if(txn[date]==undefined) {
    txn[date]={};
    txn[date].added=[];
    txn[date].withdrawn=[];
  }
  var negative=(payment.amount.charAt(0)=="-");
  if(negative) txn[date].withdrawn.push(payment.amount);
  else txn[date].added.push(payment.amount);
}

So, it's not a sum, but kinda what you've shown in the expected results.
After this code, you would have to iterate over the object's keys for the output.

You can use two objects like so:

var payments = [
{"amount": "123.00", "date": "01"},
{"amount": "123.00", "date": "01"},
{"amount": "-23.00", "date": "01"},
{"amount": "-23.00", "date": "01"},
{"amount": "23.00", "date": "01"},
{"amount": "123.00", "date": "02"},
{"amount": "123.00", "date": "02"},
{"amount": "-12.00", "date": "06"},
{"amount": "-10.00", "date": "06"},
{"amount": "-12.00", "date": "07"},
{"amount": "100.00", "date": "08"},
{"amount": "-100.00", "date": "08"},
];
var added = {};
var removed = {};
payments.forEach(p=>{
  if(p.amount > 0){
    if(+p.date in added){
      added[+p.date].push(+p.amount);
    } else {
      added[+p.date] = [+p.amount];
    }
  } else {
    if(+p.date in removed){
      removed[+p.date].push(+p.amount);
    } else {
      removed[+p.date] = [+p.amount];
    }
  }
});
var months = [,"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
var res = document.getElementById("result");
for(let i = 1; i <= 12; i++){
   if(i in added){
     if(added[i].length > 1){
     result.textContent += `In ${months[i]}[${i < 10 ? '0' + i: i}], added [${added[i].join(' + ')}] = ${added[i].reduce((acc,curr)=>acc+curr,0)}\n`;
     } else {
      result.textContent += `In ${months[i]}[${i < 10 ? '0' + i: i}], added [${added[i][0]}]\n`
     }
     if(i in removed){
        if(removed[i].length > 1){
        result.textContent += `and withdrew [${removed[i].join(' ')}] = ${removed[i].reduce((acc,curr)=>acc+curr,0)}\n`;
        } else {
          result.textContent += `and withdrew [${Math.abs(removed[i][0])}]\n`;
        }
     } else {
      result.textContent += "and no value was taken\n";
     }
   } else if(i in removed){
     if(removed[i].length > 1){
    result.textContent += `In ${months[i]}[${i < 10 ? '0' + i: i}], withdrew [${removed[i].join(' ')}] = ${removed[i].reduce((acc,curr)=>acc+curr,0)}\n`;
    } else {
      result.textContent += `In ${months[i]}[${i < 10 ? '0' + i: i}], withdrew [${Math.abs(removed[i][0])}]\n`;
    }
   }
}
<pre id="result"></pre>

this would make it completely dynamic:

txn={};
for(var payment of payments) {
if(payment.amount>=0) {
  if(txn[date]['deposit'])
    txn[date]['deposit'] += payment.amount;
  else
    txn[date]['deposit'] = payment.amount;
} else {
  if(txn[date]['withdraw'])
    txn[date]['withdraw'] += payment.amount;
  else
    txn[date]['withdraw'] = payment.amount;
}

console.log(txn);

Something like this should do you:

var months = [
  undefined,
  "Jan",
  "Feb",
  "Mar",
  "Apr",
  "May",
  "Jun",
  "Jul",
  "Aug",
  "Sep",
  "Oct",
  "Nov",
  "Dec",
];

var payments = [
    {"amount": "123.00", "date": "01"},
    {"amount": "123.00", "date": "01"},
    {"amount": "-23.00", "date": "01"},
    {"amount": "-23.00", "date": "01"},
    {"amount": "23.00", "date": "01"},
    {"amount": "123.00", "date": "02"},
    {"amount": "123.00", "date": "02"},
    {"amount": "-12.00", "date": "06"},
    {"amount": "-10.00", "date": "06"},
    {"amount": "-12.00", "date": "07"},
    {"amount": "100.00", "date": "08"},
    {"amount": "-100.00", "date": "08"},
    ];

    const summary = payments.reduce( (acc,p) => {
      const date = Number(p.date);
      const amt = Number(p.amount);

      let value = acc.get(date);
      if (!value) {
        value = { date, deposits: [], withdrawals: [], totalDeposits: 0, totalWithdrawals: 0, netChange: 0 };
        acc.set(date, value);
      }

      switch (Math.sign(amt)) {
        case -1:
          value.withdrawals.push(amt);
          value.totalWithdrawals += amt;
          break;
        case +1:
        case  0:
        default:
          value.deposits.push(amt);
          value.totalDeposits += amt;
          break;
      }
      value.netChange += amt;

      return acc;
    }, new Map() );

    for (const x of summary.values()) {
      console.log(`${months[x.date]}[${x.date}]:
  Total Deposits:    ${x.totalDeposits}    : [ ${x.deposits.join(", ")} ]
  Total Withdrawals: ${x.totalWithdrawals} : [ ${x.withdrawals.join(", ")} ]
  Net Changes:       ${x.netChange}
`, )
}

Prints this:

Jan[1]:
  Total Deposits:    269    : [ 123, 123, 23 ]
  Total Withdrawals: -46 : [ -23, -23 ]
  Net Changes:       223

Feb[2]:
  Total Deposits:    246    : [ 123, 123 ]
  Total Withdrawals: 0 : [  ]
  Net Changes:       246

Jun[6]:
  Total Deposits:    0    : [  ]
  Total Withdrawals: -22 : [ -12, -10 ]
  Net Changes:       -22

Jul[7]:
  Total Deposits:    0    : [  ]
  Total Withdrawals: -12 : [ -12 ]
  Net Changes:       -12

Aug[8]:
  Total Deposits:    100    : [ 100 ]
  Total Withdrawals: -100 : [ -100 ]
  Net Changes:       0

I like the reduce function for this case, like this:


const payments = [
  {"amount": "123.00", "date": "01"},
  {"amount": "123.00", "date": "01"},
  {"amount": "-23.00", "date": "01"},
  {"amount": "-23.00", "date": "01"},
  {"amount": "23.00", "date": "01"},
  {"amount": "123.00", "date": "02"},
  {"amount": "123.00", "date": "02"},
  {"amount": "-12.00", "date": "06"},
  {"amount": "-10.00", "date": "06"},
  {"amount": "-12.00", "date": "07"},
  {"amount": "100.00", "date": "08"},
  {"amount": "-100.00", "date": "08"},
];

const sum = (data, column, key, value) => 
  data.reduce((total, each) => {
    const number = parseFloat(each[column]);
    if(each[key] === value && number > 0)
      total += number;
    return total;
  }, 0)
;

const sub = (data, column, key, value) => 
  data.reduce((total, each) => {
    const number = parseFloat(each[column]);
    if(each[key] === value && number < 0)
      total += number;
    return total;
  }, 0)
;

console.log(sum(payments, "amount", "date", "01"));
console.log(sub(payments, "amount", "date", "01"));
Related