Reduce an arry of objects to an object with key value pairs with addition & comparision

I have an array of objects like this

const inputArray = [
  { name: "sam", date: "1 / 1 / 23", confirmed: "yes", spent: 0 },
  { name: "sam", date: "1 / 2 / 23", confirmed: "yes", spent: 4 },
  { name: "sam", date: "1 / 3 / 23", confirmed: "yes", spent: 4 },
  { name: "sam", date: "1 / 4 / 23", confirmed: "no", spent: 4 },
  { name: "bill", date: "1 / 5 / 23", confirmed: "yes", spent: 4 },
  { name: "bill", date: "1 / 6 / 23", confirmed: "yes", spent: 4 },
  { name: "bill", date: "1 / 5 / 23", confirmed: "yes", spent: 0 },
  { name: "annie", date: "1 / 6 / 23", confirmed: "yes", spent: 0 },
  { name: "annie", date: "1 / 6 / 23", confirmed: "no", spent: 2 },
  { name: "annie", date: "1 / 6 / 23", confirmed: "no", spent: 2 },
];

I want an output object like this

  • value of key spent is just an addition of all spent for a name
  • value of key confirmedAndNotSpent is just the addition of all confirmed as ‘yes’ but spent as 0 for a name
  • value of key notConfirmedAndSpent is just an addition of all confirmed as ‘no’ for a name
const outputObj = {
  sam: { spent: 12, confirmedAndNotSpent: 1, notConfirmedAndSpent: 1 },
  bill: { spent: 8, confirmedAndNotSpent: 1, notConfirmedAndSpent: 0 },
  bill: { spent: 4, confirmedAndNotSpent: 1, notConfirmedAndSpent: 2 },
};

How do I achieve this.

I tired this first

let try1 = inputArray.reduce((accumulator, current) => {
  if (!accumulator[current.name]) accumulator[current.name] = 0;
  accumulator[current.name] += +current.spent;
  return accumulator;
}, {});

This gives the the output like so { sam: 12, bill: 8, annie: 4 }.

However, I am unable to convert even this into an object with the code below.

let try2 = inputArray.reduce((accumulator, current) => {
  if (!accumulator[current.name]) accumulator[current.name] = {};
  accumulator[current.name][current.spent] += +current.spent;
  return accumulator;
}, {})

The above code gives the out put below

{
  sam: { '0': NaN, '4': NaN },
  bill: { '0': NaN, '4': NaN },
  annie: { '0': NaN, '2': NaN }
}

Can anyone help to get the output I want? Thanks.

>Solution :

Two issues with your code:

  1. You made a typo. Where you declare try2, this line:
accumulator[current.name][current.spent] += +current.spent;

should be:

accumulator[current.name].spent += +current.spent;
  1. In JavaScript, undefined + 0 (or any number) is equal to NaN. To solve this. You have to first initialize your spent property to 0:
  if (!accumulator[current.name]) accumulator[current.name] = { spent: 0 }

For the other variables, these can all be accomplished in a similar manner, just with the necessary conditional checks.

const inputArray = [
  { name: "sam", date: "1 / 1 / 23", confirmed: "yes", spent: 0 },
  { name: "sam", date: "1 / 2 / 23", confirmed: "yes", spent: 4 },
  { name: "sam", date: "1 / 3 / 23", confirmed: "yes", spent: 4 },
  { name: "sam", date: "1 / 4 / 23", confirmed: "no", spent: 4 },
  { name: "bill", date: "1 / 5 / 23", confirmed: "yes", spent: 4 },
  { name: "bill", date: "1 / 6 / 23", confirmed: "yes", spent: 4 },
  { name: "bill", date: "1 / 5 / 23", confirmed: "yes", spent: 0 },
  { name: "annie", date: "1 / 6 / 23", confirmed: "yes", spent: 0 },
  { name: "annie", date: "1 / 6 / 23", confirmed: "no", spent: 2 },
  { name: "annie", date: "1 / 6 / 23", confirmed: "no", spent: 2 },
];

let try2 = inputArray.reduce((accumulator, current) => {
  if (!accumulator[current.name]) accumulator[current.name] = {
    spent: 0,
    confirmedAndNotSpent: 0,
    notConfirmedAndSpent: 0
  };
  
  accumulator[current.name].spent += current.spent;
  
  if(current.confirmed === "yes" && current.spent === 0) {
    accumulator[current.name].confirmedAndNotSpent++;
  }
  
  if(current.confirmed === "no") {
    accumulator[current.name].notConfirmedAndSpent++;
  }
  return accumulator;
}, {})

document.getElementById("out").innerText = JSON.stringify(try2, null, 4)
<pre id="out"></p>

Leave a Reply