2

I have an array of objects, data, that I'm attempting to retrieve the total of both shoe sizes.

I'm having issues counting "size 10" apart from "size 5". I've attempted to use the .reduce() method with a conditional to only add the total count if the names match:

const data = [
    { "shoeSize": "size 10", "total": 9 },
    { "shoeSize": "size 10", "total": 3 },
    { "shoeSize": "size 5",  "total": 2 }
];

const grandTotal = data.reduce((prev, curr) => {
    return {
        shoeSize10Total: 
            prev.shoeSize === "size 10" || 
            curr.shoeSize === "size 10" && 
            prev.total + curr.total,

        shoeSize5Total: 
            prev.shoeSize === "size 5" || 
            curr.shoeSize === "size 5" && 
            prev.total + curr.total
    };
});

console.log(grandTotal);

However, the result of this method returns NaN and false - instead of the total amount of numbers for each.

I've tried looking up a solution and found something similar on this post, but they are filtering to return the value of 1; I would like to return both in an object.

This is the intended result of my .reduce():

const grandTotal = {
    shoeSize10Total: 12
    shoeSize5Total: 2
};
GROVER.
  • 4,071
  • 2
  • 19
  • 66
mattjkj
  • 123
  • 1
  • 8

6 Answers6

0

I think using .reduce here makes things too convoluted. Consider a plain loop where you increment the appropriate property an an object declared outside.

const data = [
  { shoeSize: "size 10", total: 9},
  { shoeSize: "size 10", total: 3},
  { shoeSize: "size 5", total: 2}
];

const grandTotal = {};
for (const { shoeSize, total } of data) {
  const digits = shoeSize.match(/\d+/)[0];
  if (!digits) continue;
  const key = `shoeSize${digits}Total`;
  grandTotal[key] = (grandTotal[key] || 0) + total;
}
console.log(grandTotal);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
0

We could implement basic approaches using EcmaScript Methods such as filter. Take a look at this code snippet, pal. I certainly hope this helps, buddy!

const data = [
  { shoeSize: "size 10", total: 9 },
  { shoeSize: "size 10", total: 3 },
  { shoeSize: "size 5", total: 2 },
];

let shoeSize10Total = 0;
let shoeSize05Total = 0;

const grandTotal = (data) => {
  data.filter((el) => {
    if (el.shoeSize === "size 10") {
      shoeSize10Total += el.total;
    } else {
      shoeSize05Total += el.total;
    }
  });
  return { shoeSize10Total, shoeSize05Total };
};

console.log(grandTotal(data));
Alvison Hunter
  • 620
  • 5
  • 13
0

One of issues is that you are not using the initialValue of reduce method.
Moreover, the approach to build the grandTotal is far from the best as the values are hardcoded into the reduce handler, for multiple size values that code will be a mess.
A cleaner approach is to create a mapping of input values to output keys, then in the reduce handler just to use that mapping for lookups, like this:

const data = [
  { shoeSize: "size 10", total: 9},
  { shoeSize: "size 10", total: 3},
  { shoeSize: "size 5", total: 2}
];

const map = {
  'size 5': 'shoeSize5Total',
  'size 10': 'shoeSize10Total'
};

const grandTotal = data.reduce((o, {shoeSize: s, total}) =>
  (o[map[s]] = (o[map[s]] ?? 0) + total, o), {});

console.log(grandTotal);
n--
  • 3,563
  • 4
  • 9
0

little info about below code

firstly use {} object as initial value to reduce function

now extract shoeSize from data array and use it as a key for new object

now write a condition if that key exist in new object then increment the value otherwise create a new property to object

boom at the end you will have a sorted object as a result

const data = [
    { shoeSize: "size 10", total: 9 },
    { shoeSize: "size 10", total: 3 },
    { shoeSize: "size 5", total: 2 }
]

let res = data.reduce((main,each)=>{
    let num = each.shoeSize.match(/\d+/)[0],
        newKey = `shoeSize${num}Total`,
        exist = typeof main[newKey] !== "undefined"
    if(exist){main[newKey] += each.total}
    else{main[newKey] = each.total}
    return main
},{})

console.log(res)
Amir Rahman
  • 1,076
  • 1
  • 6
  • 15
0

A simple forEach will do:

const data = [
{ shoeSize: "size 10", total: 9},
{ shoeSize: "size 10", total: 3},
{ shoeSize: "size 5", total: 2}
]

const n = {}
data.forEach(d => {
  
  const key = "Shoe" + d.shoeSize.charAt(0).toUpperCase() + d.shoeSize.slice(1).replace(" ","") + 'Total';
  const res = Object.keys(n).filter(_i => _i == key)

  if (res.length == 0) {
      n[key] = 0;    
  }
  n[key] += d.total;  
})


console.log(n)
Max Pattern
  • 1,430
  • 7
  • 18
0

I don't think .reduce is the right think to use in this problem because it makes things a little bit more complex in this situation. So I prefer always using functions to do the work for me.

function collectShoesTogether(arr) {
  var obj = {};

  arr.forEach((item) => {
    let key = `shoeSize${item.shoeSize.split(" ").join("")}Total`;

    if (obj[key] === undefined) {
      obj[key] = item.total;
    } else {
      obj[key] += item.total;
    }
  });

  return obj;
}