3
\$\begingroup\$

I have JSON data:

var data = [ { dat: 'timestamp', val: 10 }, { dat: 'timestamp', val: 20}, (...)]

Data contains objects with timestamp and value, can be more than one in month.

I need to sum values from objects which have the same month and year.

First I use each function to add additional field cat which contains formatted date in format MMM'YY for example: Sep'15, after that I group the result by this cat field. This result I map to objects with properties name and value. Values are summed by using reduce function on plucked values - val from each grouped result. I'm using underscore.

var withCategories = _.each(data, function (elem) {
 elem.cat = moment(elem.dat).format("MMM[']YY");
 });
var groupedResult = _.groupBy(withCategories , 'cat');
var finalResult = _.map(groupedResult, function (elems) {
 var valuesArray = _.pluck(elems, 'val'); // from group
 return {
 name: elems[0] ? elems[0].cat : '',
 value: _.reduce(valuesArray, function (memo, num) {
 return memo + num;
 }, 0)
 }
 });
200_success
146k22 gold badges190 silver badges479 bronze badges
asked Sep 12, 2015 at 19:47
\$\endgroup\$
0

1 Answer 1

3
\$\begingroup\$

First of all, your indentation is odd. Use a beautifier tool like JSBeautifier. If you use Sublime Text 3, there's an HTML-CSS-JS Prettifier plugin which uses the same tool internally.

Next, dat and val don't really tell anything about your data. Name it meaningfully. It's a timestamp, maybe date? And value for val? If you worry about size on transmission, just use gzip. It's better than losing hair on misnamed data.

Next, you're using moment.js in one of the loops. Moment.js is very slow based on personal experience. It tries to do as much as possible to get dates correctly, sacrificing execution speed. If you profile your code, you'll see a lot of internal extend calls in moment to generate your date. Since you're just getting year and month, why not use native getFullYear and getMonth?

Now you look like you're just operating on arrays. You can use the native array methods instead of underscore (unless you're still trying to support IE8???)

So if I understand your code correctly, this should do the same thing with lesser loops.

// Because JS doesn't have a nice way to name months because they may differ per locale
var monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
// Use reduce to aggregate your data. Pass around a hash so that we have
// direct access to groups as well as ensure groups appear just once.
var dataByMonth= data.reduce(function(dataByMonth, datum){
 var date = new Date(datum.dat);
 var value = datum.val;
 var month = monthNames[date.getMonth()];
 var year = ('' + date.getFullYear()).slice(-2);
 var group = month + '\'' + year;
 dataByMonth[group] = (dataByMonth[group] || 0) + value;
 return dataByMonth;
}, {});
// Now just turn the hash into an array.
var finalResult = Object.keys(dataObjectByMonth).map(function(group){
 return { name: group, value: dataByMonth[group] };
});
answered Sep 13, 2015 at 14:04
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.