1

I've tried to use a few different options from filter, reduce and includes but can't wrap my head round how to do this.

I have this array below of objects:

[
  { name: 'GrapeCo', weight: 0.15 },
  { name: 'MicroFit', weight: 0.5 },
  { name: 'GreenCo', weight: 0.3 },
  { name: 'GrapeCo', weight: 0.2 },
  { name: 'GrapeCo', weight: 0.3 },
  { name: 'GoldenGadgets', weight: 0.3 },
  { name: 'SpaceY', weight: 0.3 },
  { name: 'BeanzRUS', weight: 0.6 },
  { name: 'GrapeCo', weight: 0.2 },
  { name: 'SolarCorp', weight: 0.8 }
]

And I would like to find all of the duplicate named companies and merge them into one with the total weight.

So the output would be something like this:

[
  { name: 'MicroFit', weight: 0.5 },
  { name: 'GreenCo', weight: 0.3 },
  { name: 'GoldenGadgets', weight: 0.3 },
  { name: 'SpaceY', weight: 0.3 },
  { name: 'BeanzRUS', weight: 0.6 },
  { name: 'GrapeCo', weight: 0.85 },
  { name: 'SolarCorp', weight: 0.8 }
]

My reduce method that I have been trying to get to work looks like this below:

companies.reduce(
  (acc, elem) => {
     return {
        ...acc,
        [elem.name]: elem.weight + (acc[name] || 0),
     };
  },  
  {}
);
MaxwellLynn
  • 880
  • 5
  • 23
  • 46

3 Answers3

3

You can use Array.reduce to create a map by company name, then use Object.values to convert back to an array.

For example:

let a = [
  { name: 'GrapeCo', weight: 0.15 },
  { name: 'MicroFit', weight: 0.5 },
  { name: 'GreenCo', weight: 0.3 },
  { name: 'GrapeCo', weight: 0.2 },
  { name: 'GrapeCo', weight: 0.3 },
  { name: 'GoldenGadgets', weight: 0.3 },
  { name: 'SpaceY', weight: 0.3 },
  { name: 'BeanzRUS', weight: 0.6 },
  { name: 'GrapeCo', weight: 0.2 },
  { name: 'SolarCorp', weight: 0.8 }
]

let result = Object.values(a.reduce((acc, elem) => { 
    acc[elem.name] = acc[elem.name] || { name: elem.name, weight: 0 };
    acc[elem.name].weight += elem.weight;
    return acc;
}, {}));

console.log(result);
Terry Lennox
  • 29,471
  • 5
  • 28
  • 40
3

Here with reduce

let data = [
  { name: 'GrapeCo', weight: 0.15 },
  { name: 'MicroFit', weight: 0.5 },
  { name: 'GreenCo', weight: 0.3 },
  { name: 'GrapeCo', weight: 0.2 },
  { name: 'GrapeCo', weight: 0.3 },
  { name: 'GoldenGadgets', weight: 0.3 },
  { name: 'SpaceY', weight: 0.3 },
  { name: 'BeanzRUS', weight: 0.6 },
  { name: 'GrapeCo', weight: 0.2 },
  { name: 'SolarCorp', weight: 0.8 }
]

let result = data.reduce((a, { name, weight }) => {
  let i = a.findIndex(el => el.name === name);
  if(i < 0) return [...a, { name, weight }];
  a[i].weight += weight;
  return a;
}, [])

console.log(result);
bill.gates
  • 14,145
  • 3
  • 19
  • 47
3

There was a problem on companies.reduce callback. You need to use acc[elem.name] instead of acc[name].

const companies = [
  { name: 'GrapeCo', weight: 0.15 },
  { name: 'MicroFit', weight: 0.5 },
  { name: 'GreenCo', weight: 0.3 },
  { name: 'GrapeCo', weight: 0.2 },
  { name: 'GrapeCo', weight: 0.3 },
  { name: 'GoldenGadgets', weight: 0.3 },
  { name: 'SpaceY', weight: 0.3 },
  { name: 'BeanzRUS', weight: 0.6 },
  { name: 'GrapeCo', weight: 0.2 },
  { name: 'SolarCorp', weight: 0.8 }
];

const groupedBy = companies.reduce((acc, elem) => ({
  ...acc,
  [elem.name]: elem.weight + (acc[elem.name] || 0)
}), {});
const result = Object.entries(groupedBy).map(([ name, weight ]) => ({
  name,
  weight: parseFloat(weight.toFixed(2))
}));
console.log(result);
Derek Wang
  • 10,098
  • 4
  • 18
  • 39