Reputation: 335
So i've been struggling for a few hours now. Here's what I'm trying to do.
I have an array of objects:
initArr = [
{id: 5, time: 100, download: true},
{id: 2, time: 50, download: false},
{id: 3, time: 1000, download: true},
{id: 5, time: 50, download: true},
{id: 5, time: 550, download: false},
{id: 2, time: 1500, download: true}
]
some objects have the same id
, I want to merge them together.
- but when merging i want to sum the time
value of both merged object .
- if one of the two merged objects has download: false
, the merged object should have false
, otherwise true
.
Here's what I have so far (I did not start yet even considering the download key):
const mergedArr= [];
initArr.map(obj => obj['id'])
.map((id, i, arr) => {
if (arr.indexOf(id) === i) {
mergedArr.push(initArr[i]);
} else {
const mergeIndex = mergedArr.map( x => x.id).indexOf(id);
mergedArr[mergeIndex].playTime +=initArr[arr.indexOf(id)].playTime;
}
return mergedArr
});
I'd love so inputs or hints :)
Upvotes: 2
Views: 114
Reputation: 1
function manipulation(initArr){
var resultArray = [];
var arrMap = new Map();
var currIndex = 0;
initArr.forEach(function(item, index){
if(arrMap.has(item.id)){
var existingItem = resultArray[arrMap.get(item.id)];
existingItem.time = item.time+existingItem.time;
if(existingItem.download && !item.download){
existingItem.download = false;
}
}else{
arrMap.set(item.id, currIndex);
resultArray.push(item);
currIndex++;
}
})
return resultArray;
}
Upvotes: 0
Reputation: 191976
Reduce the array to a Map by the object's id
, and then convert back to array using Map.values()
and Array.from()
(or by spreading into an array).
Note: in this case using Map as an accumulator is better than using an object, since the id
property is numeric. In ES6 objects usually maintain the order of insertion, unless the properties are numeric. When an object with numeric property keys is convert to an array, the numeric properties come first, and they are ordered by their value. On the other hand, a Map always maintains the order of insertion.
const initArr = [
{id: 5, time: 100, download: true},
{id: 2, time: 50, download: false},
{id: 3, time: 1000, download: true},
{id: 5, time: 50, download: true},
{id: 5, time: 550, download: false},
{id: 2, time: 1500, download: true}
]
const result = Array.from(initArr.reduce((r, o) => {
if(!r.has(o.id)) r.set(o.id, { ...o });
else {
const current = r.get(o.id);
current.time += o.time;
current.download = current.download && o.download
}
return r;
}, new Map).values());
console.log(result);
Upvotes: 1
Reputation: 2085
Try this, supports download option as well
const arr = [
{id: 5, time: 100, download: true},
{id: 2, time: 50, download: false},
{id: 3, time: 1000, download: true},
{id: 5, time: 50, download: true},
{id: 5, time: 550, download: false},
{id: 2, time: 1500, download: true}
]
const result = arr.reduce((res, obj) => {
const found = res.find(t => t.id === obj.id);
if(found){
found.time += obj.time;
found.download = found.download && obj.download;
} else {
res.push(obj);
}
return res;
}, []);
console.log(result);
Upvotes: 1
Reputation: 35222
You could reduce
the array. Create an accumulator object with each id
as key and the merged object as value. If the id
already exists, update time
and download
with current object. Else, add the current id
as key and set a copy of the current object as it's value. Then use Object.values()
to get an array of values from this accumulator object.
const initArr = [
{ id: 5, time: 100, download: true },
{ id: 2, time: 50, download: false },
{ id: 3, time: 1000, download: true },
{ id: 5, time: 50, download: true },
{ id: 5, time: 550, download: false },
{ id: 2, time: 1500, download: true }
]
const merged = initArr.reduce((acc, o) => {
if (acc[o.id]) {
acc[o.id].time += o.time;
acc[o.id].download = acc[o.id].download && o.download;
} else
acc[o.id] = { ...o };
return acc;
}, {})
console.log(Object.values(merged))
Upvotes: 2
Reputation: 10882
One more reduce
solution:
const initArr = [
{id: 5, time: 100, download: true},
{id: 2, time: 50, download: false},
{id: 3, time: 1000, download: true},
{id: 5, time: 50, download: true},
{id: 5, time: 550, download: false},
{id: 2, time: 1500, download: true}
]
const merged = initArr.reduce((a,c) => {
const found = a.find(x => x.id === c.id);
if (found) {
found.time += c.time;
found.download = found.download && c.download;
return a;
}
return [...a, {...c}];
}, []);
console.log(merged);
Upvotes: 0
Reputation: 6446
You can use reduce to:
else
const arr = [
{id: 5, time: 100, download: true},
{id: 2, time: 50, download: false},
{id: 3, time: 1000, download: true},
{id: 5, time: 50, download: true},
{id: 5, time: 550, download: false},
{id: 2, time: 1500, download: true}
]
console.log(arr.reduce((a, o) => {
const i = a.findIndex(({id}) => id === o.id)
i + 1 ? a[i].time += o.time : a.push(o)
return a
}, []))
Upvotes: 0