perf: optimize performance statistics computation
[e-mobility-charging-stations-simulator.git] / src / utils / StatisticUtils.ts
index bb9a847091decf2ca488f83ad8c3d9d579d6e7fd..3f587caaaf46c753d080b1cccc13fab131dacaba 100644 (file)
@@ -1,7 +1,31 @@
-import { Utils } from './Utils';
+import { isEmptyArray, isNullOrUndefined } from './Utils';
 
+/**
+ * Computes the average of the given data set.
+ *
+ * @param dataSet - Data set.
+ * @returns The average of the given data set.
+ * @internal
+ */
+export const average = (dataSet: number[]): number => {
+  if (Array.isArray(dataSet) && dataSet.length === 0) {
+    return 0;
+  }
+  if (Array.isArray(dataSet) && dataSet.length === 1) {
+    return dataSet[0];
+  }
+  return dataSet.reduce((accumulator, nb) => accumulator + nb, 0) / dataSet.length;
+};
+
+/**
+ * Computes the median of the given data set.
+ *
+ * @param dataSet - Data set.
+ * @returns The median of the given data set.
+ * @internal
+ */
 export const median = (dataSet: number[]): number => {
-  if (Utils.isEmptyArray(dataSet)) {
+  if (isEmptyArray(dataSet)) {
     return 0;
   }
   if (Array.isArray(dataSet) === true && dataSet.length === 1) {
@@ -18,7 +42,7 @@ export const nthPercentile = (dataSet: number[], percentile: number): number =>
   if (percentile < 0 && percentile > 100) {
     throw new RangeError('Percentile is not between 0 and 100');
   }
-  if (Utils.isEmptyArray(dataSet)) {
+  if (isEmptyArray(dataSet)) {
     return 0;
   }
   const sortedDataSet = dataSet.slice().sort((a, b) => a - b);
@@ -30,7 +54,7 @@ export const nthPercentile = (dataSet: number[], percentile: number): number =>
   }
   const percentileIndexBase = (percentile / 100) * (sortedDataSet.length - 1);
   const percentileIndexInteger = Math.floor(percentileIndexBase);
-  if (!Utils.isNullOrUndefined(sortedDataSet[percentileIndexInteger + 1])) {
+  if (!isNullOrUndefined(sortedDataSet[percentileIndexInteger + 1])) {
     return (
       sortedDataSet[percentileIndexInteger] +
       (percentileIndexBase - percentileIndexInteger) *
@@ -40,16 +64,11 @@ export const nthPercentile = (dataSet: number[], percentile: number): number =>
   return sortedDataSet[percentileIndexInteger];
 };
 
-export const stdDeviation = (dataSet: number[]): number => {
-  let totalDataSet = 0;
-  for (const data of dataSet) {
-    totalDataSet += data;
-  }
-  const dataSetMean = totalDataSet / dataSet.length;
-  let totalGeometricDeviation = 0;
-  for (const data of dataSet) {
-    const deviation = data - dataSetMean;
-    totalGeometricDeviation += deviation * deviation;
-  }
-  return Math.sqrt(totalGeometricDeviation / dataSet.length);
+export const stdDeviation = (dataSet: number[], dataSetAverage?: number): number => {
+  dataSetAverage = dataSetAverage ?? average(dataSet);
+  const geometricDeviation = dataSet.reduce((accumulator, nb) => {
+    const deviation = nb - dataSetAverage!;
+    return accumulator + deviation * deviation;
+  }, 0);
+  return Math.sqrt(geometricDeviation / dataSet.length);
 };