Reputation: 906
I got array of objects (tasks). Each task has property named 'category' and 'duration'.
var tasks = [
{
_id : "123",
category : "someCategory",
duration: "3432"
},
{
_id : "113",
category : "someCategory",
duration: "23"
},
{
_id : "124",
category : "someCategory 2",
duration: "1343"
},
{
_id : "2124",
category : "someCategory 2",
duration: "1343"
},
{
_id : "7124",
category : "someCategory 5",
duration: "53"
},
{
_id : "34",
category : "someCategory",
duration: "753"
}
]
I'd like to group tasks by category (unique) and sum duration of each category.
Result should be like:
var categories = ["someCategory", "someCategory 2" ... ]
var duration = [ <summary duration of "someCategory">, <summary duration of "someCategory 2">, ... ]
I have groupBy function which gives me all categories. I can find uniqueCategories using Array.prototype.filter but still I have to sum 'duration'.
var categoryMap = groupBy(tasks, 'category');
var uniqueCategories = categoryMap.get('category').filter((x, i, a) => a.indexOf(x) == i);
function groupBy(list, property) {
var map = new Map();
list.forEach(function(item) {
const key = property;
if(!map.has(key)) {
map.set(key, [item[key]])
} else {
map.get(key).push(item[key])
}
})
return map;
}
Then I create array of { key : value } and sum by key i.e.
[
{
someCategory : 3432
},
{
someCategory : 23
}
.
.
.
]
Finally I achieve my goal but code looks messy and isn't readable at all... Is there better approach to do it in Javascript?
Upvotes: 0
Views: 4197
Reputation: 41893
var tasks = [{"_id":"123","category":"someCategory","duration":"3432"},{"_id":"113","category":"someCategory","duration":"23"},{"_id":"124","category":"someCategory 2","duration":"1343"},{"_id":"2124","category":"someCategory 2","duration":"1343"},{"_id":"7124","category":"someCategory 5","duration":"53"},{"_id":"34","category":"someCategory","duration":"753"}]
var arr = [];
tasks.forEach(v => arr.push(v.category));
var newArr = [...new Set(arr)];
var arr2 = [];
newArr.forEach(function(v) {
var obj = {};
obj.category = v;
obj.duration = 0;
arr2.push(obj);
});
arr2.forEach(v => tasks.forEach(c => c.category == v.category ? v.duration += parseInt(c.duration) : v));
console.log(arr2);
Upvotes: 2
Reputation: 122047
You could just return one object with category: duration
.
var tasks = [{"_id":"123","category":"someCategory","duration":"3432"},{"_id":"113","category":"someCategory","duration":"23"},{"_id":"124","category":"someCategory 2","duration":"1343"},{"_id":"2124","category":"someCategory 2","duration":"1343"},{"_id":"7124","category":"someCategory 5","duration":"53"},{"_id":"34","category":"someCategory","duration":"753"}]
var result = tasks.reduce(function(r, e) {
r[e.category] = (r[e.category] || 0) + +e.duration
return r;
}, {})
console.log(result)
Upvotes: 3