Reputation: 337
I have a dataset like this:
var ds = [
{time: "t1", parameter_q: "value1"},
{time: "t2", parameter_q: "value2"},
{time: "t3", parameter_q: "value3"},
....
];
The dataset contains hourly values and the date/time format is dd/mm/yyyy hh:mm:ss
I'm looking for a way to calculate the daily average of the values (attribute parameter_q) with vintage JavaScript.
I've made a start with a function like this:
function calcDAvg(ds) {
for (var i = 0; i < ds.length ; i++){
ds[i].uday = (ds[i].xtime.getMonth() + 1) + "/" + ds[i].xtime.getDate() + "/" + ds[i].xtime.getFullYear();
};
var dailyaverage = [];
var avgqarray = [];
var hourAry = [];
var checkday = undefined;
//defining temporal array
var tmpAry = [];
var hours = 0;
for (var i = 0; i < ds.length ; i++) {
var tmpObj = new Object();
var iday = ds[i].uday;
if (iday != checkday ) {
avgqarray.push(foo); //foo: function to calculate the average of tmpAry
tmpObj.xtime = new Date(iday);
dailyaverage.push(tmpObj);
tmpAry = [];
checkday = iday;
tmpAry.push(ds[i].parameter_q);
hourAry.push(hours);
hours = 1;
} else {
tmpAry.push(ds[i].parameter_q);
hours++;
}
}
return dailyaverage;
}
I've noticed that the last timestep in the dataset is ignored and that's not what I expected. Otherwise, I cannot believe that this is most elegant way to calculate a daily average of a dataset in JavaScript. Is there a more elegant way?
Any help is appreciated.
Upvotes: 0
Views: 1504
Reputation: 5245
When looping through the data as you do, it is always important to process any data remaining in the buffers after the loop completes. This might be the cause of your error.
Below is an attempt at somewhat cleaner code for doing this. It leverages the reduce function to create a dictionary of averages per date. While this approach might suffer in performance slightly, it does not require that the data is in time order.
function calcDAvg(ds) {
var groups = ds.reduce(function(acc,cur) {
var key = (cur.xtime.getMonth() + 1) + "/" + cur.xtime.getDate() + "/" + cur.xtime.getFullYear();
if (acc[key]) {
acc[key].sum += cur.parameter_q;
acc[key].count++;
} else {
acc[key] = { sum: cur.parameter_q, count: 1 };
}
}, {});
var dailyAverage = [];
for (var key in groups)
{
dailyAverage.push(groups[key].sum / groups[key].count);
}
return dailyAverage;
}
Upvotes: 0
Reputation: 147413
Given a date format of dd/mm/yyyy hh:mm:ss, you can group by the date part, then calculate the average, e.g.
var ds = [
{time: "01/06/2018 10:00:00", parameter_q: "25"},
{time: "01/06/2018 11:00:00", parameter_q: "30"},
{time: "01/06/2018 12:00:00", parameter_q: "35"},
{time: "02/06/2018 10:00:00", parameter_q: "28"},
{time: "02/06/2018 11:00:00", parameter_q: "38"},
{time: "02/06/2018 12:00:00", parameter_q: "48"}
];
function getAverages(data) {
var sums = data.reduce(function(acc, obj) {
var date = obj.time.split(' ')[0];
if (!acc[date]) {
acc[date] = {sum:0, count:0};
}
acc[date].sum += +obj.parameter_q;
acc[date].count++;
return acc;
}, Object.create(null));
return Object.keys(sums).map(function(date) {
return {[date]:sums[date].sum/sums[date].count};
});
}
console.log(getAverages(ds));
You could do much the same thing with forEach. Don't be tempted to convert the date strings to Dates, I don't think it's necessary.
Upvotes: 1