I have an array of objects(shopping cart) and I want to remove duplicates that have same obj.id and obj.arr an empty array.After that to increase obj.quantity by one.
Here is the original arr:
const cart = [
{
"id": 1,
"name": "book",
"arr": [],
"quantity": 1
},
{
"id": 2,
"name": "pen",
"arr": ["asa", "asd"],
"quantity": 3
},
{
"id": 1,
"name": "book",
"arr": [],
"quantity": 1
},
{
"id": 3,
"name": "ball pen",
"arr": ["azx", "dcv"],
"quantity": 1
}
]
Expected output should be like this:
const cart = [
{
"id": 1,
"name": "book",
"arr": [],
"quantity": 2
},
{
"id": 2,
"name": "pen",
"arr": ["asa", "asd"],
"quantity": 3
},
{
"id": 3,
"name": "ball pen",
"arr": ["azx", "dcv"],
"quantity": 1
}
]
I don't know how to update object.quantity after removing the duplicate. And if possible I want to keep the item with smallest index.
Could you please help me?
Thank you
Modified code from How to remove all duplicates from an array of objects?.
instead of filter I used reduce to then find and update the quantity of the duplicated item
const cart = [
{
"id": 1,
"name": "book",
"arr": [],
"quantity": 1
},
{
"id": 2,
"name": "pen",
"arr": ["asa", "asd"],
"quantity": 3
},
{
"id": 1,
"name": "book",
"arr": [],
"quantity": 1
},
{
"id": 3,
"name": "ball pen",
"arr": ["azx", "dcv"],
"quantity": 1
}
]
function findDupUpdateQty(arr){
return arr.reduce((acc, currentVal, index, self) => {
if(index === self.findIndex((e)=> e.id === currentVal.id && e.arr.length === currentVal.arr.length)){
acc.push(currentVal)
} else {
//if there's a duplicate then update quanitity
acc[acc.findIndex((e)=> e.id === currentVal.id && e.arr.length === currentVal.arr.length)].quantity += currentVal.quantity
}
return acc
},[])
}
console.log(findDupUpdateQty(cart))
Edits with some of @Corrl suggestions:
const cart = [
{
"id": 1,
"name": "book",
"arr": [],
"quantity": 1
},
{
"id": 2,
"name": "pen",
"arr": ["asa", "asd"],
"quantity": 3
},
{
"id": 1,
"name": "book",
"arr": [],
"quantity": 1
},
{
"id": 3,
"name": "ball pen",
"arr": ["azx", "dcv"],
"quantity": 1
}
]
function findDupUpdateQty(arr){
return arr.reduce((acc, currentVal, index, self) => { //check if both arrays are the same
let firstFoundIndex = self.findIndex((e)=> e.id === currentVal.id && JSON.stringify(e.arr) === JSON.stringify(currentVal.arr))
if(index === firstFoundIndex){
acc.push(currentVal)
} else {
self[firstFoundIndex].quantity += currentVal.quantity
}
return acc
},[])
}
console.log(findDupUpdateQty(cart))
To keep the order I would
const cart = [{
"id": 1,
"name": "book",
"arr": [],
"quantity": 1
}, {
"id": 2,
"name": "pen",
"arr": ["asa", "asd"],
"quantity": 3
}, {
"id": 1,
"name": "book",
"arr": [],
"quantity": 1
}, {
"id": 3,
"name": "ball pen",
"arr": ["azx", "dcv"],
"quantity": 1
}]
function removeDuplicates(cart) {
let map = new Map()
// groupBy id
cart.forEach(obj => {
let entry = map.has(obj.id)
if (entry) {
let value = map.get(obj.id)
map.set(obj.id, [...value, obj])
} else {
map.set(obj.id, [obj])
}
})
map.forEach((value, key) => {
// doubles?
if (value.length > 1) {
let allEmptyArrays = value.every(obj => obj.arr.length === 0)
if (allEmptyArrays) {
// keep only the first value
let keepValue = value[0]
// adjust quantity
keepValue.quantity++
// overwrite existing entry
map.set(key, [keepValue])
}
}
})
// rebuild cart
return Array.from(map).map(([_, value]) => value[0])
}
console.log(removeDuplicates(cart))
Thank you both!
I was planing to use one of your answers inside of selector(createSelector) from 'reselect' library. But looks like, it is incrementing obj.quantity, for all products, not only for those with obj.arr an empty array.
So I did more research, and I changed my addToCartReducer, based on this post. Now all the action is happening inside the reducer, not inside the selector. Every time I add to cart a product with obj.arr an empty array it increments its quantity by 1.