I've got array of fruits:
const fruits = [
{ name: 'apple', count: 2 },
{ name: 'apple', count: 4 },
{ name: 'banana', count: 5 },
{ name: 'apple', count: 3 },
{ name: 'apple', count: 4 },
{ name: 'apple', count: 1 },
{ name: 'banana', count: 3 },
{ name: 'apple', count: 1 },
{ name: 'orange', count: 2 }
];
What I try to achieve is to reduce this array so it look like this:
let fruitsReduces = [
{ name: 'apple', count: 15 },
{ name: 'banana', count: 8 },
{ name: 'orange', count: 2 }
];
I've done this using very ugly for
loop:
for (let i = 0; i < fruits.length; i++) {
fruitItem = {};
fruitItem.name = fruits[i].name;
fruitItem.count = fruits[i].count;
const fruitAlreadyInTheArray = fruitsReduced.find(fruit => fruit.name === fruitItem.name);
if (!fruitAlreadyInTheArray) {
fruitsReduced.push(fruitItem);
} else {
fruitAlreadyInTheArray.count += fruitItem.count;
}
}
But I'm sure that same thing can be done somehow by using ES6 array.reduce
. Can you help me?
I looked at JS (ES6): Reduce array based on object attribute but I can't figure it out.
You can us reduce()
the array into an object. Use Object.values()
to convert the object into an array.
const fruits = [{"name":"apple","count":2},{"name":"apple","count":4},{"name":"banana","count":5},{"name":"apple","count":3},{"name":"apple","count":4},{"name":"apple","count":1},{"name":"banana","count":3},{"name":"apple","count":1},{"name":"orange","count":2}];
var result = Object.values(fruits.reduce((c, {name,count}) => {
c[name] = c[name] || {name,count: 0};
c[name].count += count;
return c;
}, {}));
console.log(result);
You could use an array as accumulator and seach for an inserted object with a wanted name for adding the actual count. If not found add a new object.
const
fruits = [{ name: 'apple', count: 2 }, { name: 'apple', count: 4 }, { name: 'banana', count: 5 }, { name: 'apple', count: 3 }, { name: 'apple', count: 4 }, { name: 'apple', count: 1 }, { name: 'banana', count: 3 }, { name: 'apple', count: 1 }, { name: 'orange', count: 2 }],
result = fruits.reduce((r, { name, count }) => {
var item = r.find(o => o.name === name);
if (!item) {
item = { name, count: 0 };
r.push(item);
}
item.count += count;
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A different approach by collecting all counts first with a Map
and render the wanted array with Array.from
and a mapping function which builds new objects.
const
fruits = [{ name: 'apple', count: 2 }, { name: 'apple', count: 4 }, { name: 'banana', count: 5 }, { name: 'apple', count: 3 }, { name: 'apple', count: 4 }, { name: 'apple', count: 1 }, { name: 'banana', count: 3 }, { name: 'apple', count: 1 }, { name: 'orange', count: 2 }],
result = Array.from(
fruits.reduce(
(m, { name, count }) => m.set(name, (m.get(name) || 0) + count),
new Map
),
([name, count]) => ({ name, count })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With