I want to return new array by using reduce. For example,
const product = [
{ color: 'orange', type: 'hat', count: 1 },
{ color: 'orange', type: 'hat', count: 1 },
{ color: 'orange', type: 'shoes', count: 1 },
{ color: 'blue', type: 'food', count: 1 },
];
the product list need to like below because there are two 'hat' therefore, the count should be 2 and one { color: 'orange', type: 'hat', count: 1 } should be removed.
const result = product.reduce((acc, curr) => {
// I want to make new array like
// const product = [
// { color: 'orange', type: 'hat', count: 2 },
// { color: 'orange', type: 'shoes', count: 1 },
// { color: 'blue', type: 'food', count: 1 },
//];
return acc
}
thank you!
I would do it the following way :
curr arraycountNote : I've used the Spread operator to make a deep copy of the object instead of pushing the current object into the array.
This result by not modifying the products array and create a completely new array
const product = [
{ color: 'orange', type: 'hat', count: 1 },
{ color: 'orange', type: 'hat', count: 1 },
{ color: 'orange', type: 'shoes', count: 1 },
{ color: 'blue', type: 'food', count: 1 },
];
const result = product.reduce((acc, curr) => {
if(!acc) return [...curr]
const exist = acc.find(x => x.type === curr.type && x.color === curr.color)
exist ? exist.count += 1 : acc.push({...curr})
return acc
}, [])
console.log(result)
You can try it
const product = [
{ color: 'orange', type: 'hat', count: 1 },
{ color: 'orange', type: 'hat', count: 1 },
{ color: 'orange', type: 'shoes', count: 1 },
{ color: 'blue', type: 'food', count: 1 },
];
const result = product.reduce((res, obj) => {
let exist = res.find(o => o.color === obj.color && o.type === obj.type)
if (exist) {
exist.count += obj.count
} else {
res = [...res, {...obj}]
}
return [...res]
}, [])
console.log(result)
console.log(product)
Update Edit with suggestion by yassine-el-bouchaibi
From the above comment ...
The task also could be described as grouping, merging and aggregating. It is a quite common task and can be solved by a generically implemented but customizable reducer function ... see ... "How to group and merge array entries and to sum-up values on multiple common (but not all) keys?"
... prove ...
function groupMergeAndAggregateGenerically(collector, item) {
const {
createKey, createMerger, aggregate,
lookup, result = [],
} = collector;
const key = createKey(item);
let merger = lookup.get(key) ?? null;
if (merger === null) {
merger = createMerger(item);
lookup.set(key, merger);
result.push(merger);
}
aggregate(merger, item);
return collector;
}
const productData = [
{ color: 'orange', type: 'hat', count: 1 },
{ color: 'orange', type: 'hat', count: 1 },
{ color: 'orange', type: 'shoes', count: 1 },
{ color: 'blue', type: 'food', count: 1 },
];
const { result: mergedData } = productData
.reduce(groupMergeAndAggregateGenerically, {
createKey: ({ color, type }) => [color, type].join('_'),
createMerger: ({ color, type }) => ({ color, type, count: 0 }),
aggregate: (merger, { count }) => merger.count += count,
lookup: new Map,
result: [],
});
console.log({ mergedData, productData });
.as-console-wrapper { min-height: 100%!important; top: 0; }