@testyard/stats
Version:
Value stats tester.
155 lines (152 loc) • 5.24 kB
JavaScript
/*!
* @testyard/stats v1.4.1
* https://github.com/testyardjs/stats
*
* Copyright (c) 2023 Richard King <richrdkng@gmail.com> (https://richrdkng.com)
* Released under the MIT License
* https://github.com/testyardjs/stats/blob/main/LICENSE
*
* Date: 2023-07-19T13:11:26.750Z
*/
'use strict';
const cutToDecimals = (num, decimals = 1) => {
const factor = Math.pow(10, decimals);
return Math.floor(num * factor) / factor;
// return parseFloat(num.toFixed(decimals))
};
class FloatStats {
constructor() {
this._result = {};
this._numEntries = 0;
this._lowestValue = NaN;
this._highestValue = NaN;
this._sumValue = NaN;
this._numAdded = 0;
this._isSummarized = false;
this.add = (num, decimals = 1) => {
// console.log('input', num)
// num = parseFloat(num.toFixed(decimals + 2))
// num = Math.round((num + Number.EPSILON) * 1000) / 1000
num = cutToDecimals(num, decimals);
// console.log('formatted', num)
if (!(num in this._result)) {
this._result[num] = 0;
}
this._result[num]++;
this._numAdded++;
};
}
get result() {
// @ts-expect-error
const object = {
of: (num) => {
this._summarize();
if (!(num in this._result)) {
throw new Error(`num ${num} is not in the results.`);
}
return this._result[num];
}
};
const props = {
entries: {
get: () => {
this._summarize();
return { ...this._result };
}
},
floats: {
get: () => {
this._summarize();
return Object
.keys(this._result)
.map(value => parseFloat(value))
.sort((a, b) => a - b);
}
},
numEntries: {
get: () => {
this._summarize();
return this._numEntries;
}
},
lowestValue: {
get: () => {
this._summarize();
return this._lowestValue;
}
},
highestValue: {
get: () => {
this._summarize();
return this._highestValue;
}
},
averageValue: {
get: () => {
this._summarize();
return this._sumValue / this._numEntries;
}
},
firstEntry: {
get: () => {
this._summarize();
const floats = Object.keys(this._result)
.map(value => parseFloat(value))
.sort((a, b) => a - b);
return {
value: floats[0],
percent: this._result[floats[0]]
};
}
},
lastEntry: {
get: () => {
this._summarize();
const floats = Object.keys(this._result)
.map(value => parseFloat(value))
.sort((a, b) => a - b);
return {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
value: floats.at(-1),
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
percent: this._result[floats.at(-1)]
};
}
}
};
Object.defineProperties(object, props);
return object;
}
_summarize() {
if (!this._isSummarized) {
for (const [key, value] of Object.entries(this._result)) {
this._result[key] = value / this._numAdded;
}
this._numEntries = Object.keys(this._result).length;
for (const value of Object.values(this._result)) {
// eslint-disable-next-line no-self-compare
if (this._lowestValue !== this._lowestValue) {
this._lowestValue = value;
}
if (this._lowestValue > value) {
this._lowestValue = value;
}
// eslint-disable-next-line no-self-compare
if (this._highestValue !== this._highestValue) {
this._highestValue = value;
}
if (this._highestValue < value) {
this._highestValue = value;
}
// eslint-disable-next-line no-self-compare
if (this._sumValue !== this._sumValue) {
this._sumValue = 0;
}
this._sumValue += value;
}
this._isSummarized = true;
}
}
}
module.exports = FloatStats;
//# sourceMappingURL=index.js.map