Reputation: 1415
I'm trying to merge every object with a duplicate 'name' property, and by merge, I mean adding their 'value' property together and removing the duplicate one.
For some reason my code doesn't give expected results:
array = [
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
]
for (let i = 0; i < array.length; i++) {
for (let y = 0; y < array.length; y++) {
if (array[y].name == array[i].name) {
array[i].value = parseInt(array[i].value) + parseInt(array[y].value)
array.splice(y,1)
}
}
}
console.log(array)
// gives result [ { name: '5', value: 30 }, { name: 'f', value: '10' } ]
// expected results [ { name: '5', value: 30 }, { name: 'f', value: '30' } ]
Upvotes: 1
Views: 445
Reputation: 101748
This is happening because you are not ensuring that y
and i
are different when you update the element at i
and removing the one at y
. So you having a situation where you are modifying an item and then immediately removing it.
There are much better ways to do this, but here is a simple way to fix what you already have:
let array = [
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
]
for (let i = 0; i < array.length; i++) {
for (let y = 0; y < array.length; y++) {
// v-- ensure y and i are not the same
if (y !== i && array[y].name === array[i].name) {
array[i].value = parseInt(array[i].value) + parseInt(array[y].value)
array.splice(y,1)
}
}
}
console.log(array)
Upvotes: 0
Reputation: 164960
Looks like a job for Array.prototype.reduce
and Array.prototype.map
.
First thing to do is generate a Map
of names to cumulative values.
Then you can convert that into an array of objects with the names and totals.
const array = [
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
{ name: 'f', value: '10' },
{ name: '5', value: '10' }
]
const totals = array.reduce((map, item) => map.set(
item.name, parseInt(item.value) + (map.get(item.name) || 0)
), new Map())
const merged = Array.from(totals)
.map(([name, value]) => ({ name, value }))
console.info('Merged', merged)
Note: Map
iteration is in insertion order so "f" will be first, followed by "5". If you need to change the order, Array.prototype.sort
should be employed.
Upvotes: 1
Reputation: 2592
The issue here is that you are iterating and updating the same array due to which when you remove the index the array indices shift and you miss few of the elements. Try the below code:
array = [
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
]
newArray = [];
for (let i = 0; i < array.length; i++) {
var found=false;
for(let j= 0;j<newArray.length;j++) {
if(newArray[j].name == array[i].name) {
newArray[j].value = parseInt(array[i].value)+ parseInt(newArray[j].value);
found = true;
break;
}
}
if(!found) {
newArray.push(array[i]);
}
}
console.log(newArray);
Upvotes: 0
Reputation: 9305
Use a combination of reduce
and map
to do this:
let array = [
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
{ name: 'f', value: '10' },
{ name: '5', value: '10' },
];
let resultObj = array.reduce((result, item) => {
result[item.name] = (result[item.name] || 0) + (Number(item.value) || 0);
return result;
}, {});
let resultArray = Object.getOwnPropertyNames(resultObj).map(name => {
return {name, value: resultObj[name]}
})
console.log(resultArray)
Upvotes: 3