Reputation: 1916
I have an average()
method to calculate the average between two values.
The averages are coming off by a "hair" of a decimal value.
const measurements = [
{ timestamp: '2015-09-01T16:00:00.000Z',
temperature: 27.1,
dewPoint: 16.9
},
{ timestamp: '2015-09-01T16:10:00.000Z',
temperature: 27.3,
dewPoint: 0
},
{ timestamp: '2015-09-01T16:20:00.000Z',
temperature: 27.5,
dewPoint: 17.1
},
{ timestamp: '2015-09-01T16:30:00.000Z',
temperature: 27.4,
dewPoint: 17.3
},
{ timestamp: '2015-09-01T16:40:00.000Z',
temperature: 27.2,
dewPoint: 0
},
{ timestamp: '2015-09-01T17:00:00.000Z',
temperature: 28.1,
dewPoint: 18.3
}
]
For sake of conciseness, I'm not gonna share 60 lines of code here:
Assumptions:
I have a query()
method to get ranges from and to a given timestamp. In my example from 2015-09-01T16:00:00.000Z
to 2015-09-01T17:00:00.000Z
Another method loops through the object and outputs the min and max values with a specified metric. My metric is dewPoint the min and max values of the above array is 16.9 and 18.3 respectively.
Finally (see below) a method to get the average between min and max values
Therefore this is the result of the explanation above:
// POSTMAN result
[
{
"metric": "dewPoint",
"stat": "min",
"value": 16.9
},
{
"metric": "dewPoint",
"stat": "max",
"value": 18.3
},
{
"metric": "dewPoint",
"stat": "average",
"value": 17.4
}
]
I want to get the average between the max and min values. i.e. 16.9
& 18.3
which should be 17.6, however, I'm getting 17.4 instead
Here's the one method that has the actual bug.
function averageMetric(measurements, metric) {
// => metric dewPoint
// => measurements = the data array in example
let value = 0
let measurementsWithMetric = 0
measurements.forEach(measurement => {
if (measurement[metric]) {
value += measurement[metric]
measurementsWithMetric++
}
})
//=> value = 69.6
//=> measurementsWithMetric = 4
const average = value / measurementsWithMetric // Is this the issue?
// average = 17.4
return isNaN(average) ? null : Math.round(average * 100) / 100
}
Could you help me understand the issue here and also suggest an ES6 equivalent solution of the method above?
Upvotes: 0
Views: 71
Reputation: 115
measurements.forEach(measurement => {
if (measurement[metric]) {
value += measurement[metric]
measurementsWithMetric++
}
})
is incorrect if you want to get the average of the min and max, (which is the mid range)
Instead, you should try
let min = 10**6, max = -10**6; //unless your dew point is stupid this should be fine
measurements.forEach(measurement => {
if (measurement[metric]) {
min = Math.min(measurement[metric], min);
max = Math.max(measurement[metric], max);
measurementsWithMetric++
}
})
let average = (max+min)/2;
Upvotes: 0
Reputation: 20269
Your function calculates the arithmetic mean, not the mid-range. Here is a function to calculate that:
const measurements = [
{temperature: 27.1, dewPoint: 16.9},
{temperature: 27.3, dewPoint: 0}, // Isn't this the minimum value though?
{temperature: 27.5, dewPoint: 17.1},
{temperature: 27.4, dewPoint: 17.3},
{temperature: 27.2, dewPoint: 0},
{temperature: 28.1, dewPoint: 18.3},
{temperature: 28.2}
];
function averageMetric(meas, metr) {
const valid = meas.filter(e => e[metr]);
const min = Math.min(...valid.map(e => e[metr]));
const max = Math.max(...valid.map(e => e[metr]));
return (min + max) / 2;
}
console.log(averageMetric(measurements, 'dewPoint'));
Upvotes: 2