@naturalcycles/js-lib 14.73.0 → 14.74.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,6 +24,10 @@ export declare function _averageWeighted(values: number[], weights: number[]): n
24
24
  * // 3
25
25
  */
26
26
  export declare function _percentile(values: number[], pc: number): number;
27
+ /**
28
+ * A tiny bit more efficient function than calling _percentile individually.
29
+ */
30
+ export declare function _percentiles(values: number[], pcs: number[]): Record<number, number>;
27
31
  /**
28
32
  * @example
29
33
  *
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports._median = exports._percentile = exports._averageWeighted = exports._average = void 0;
3
+ exports._median = exports._percentiles = exports._percentile = exports._averageWeighted = exports._average = void 0;
4
4
  const number_util_1 = require("../number/number.util");
5
5
  /**
6
6
  * @returns Average of the array of numbers
@@ -45,6 +45,23 @@ function _percentile(values, pc) {
45
45
  return _averageWeighted([sorted[floorPos], sorted[ceilPos]], [1 - dec, dec]);
46
46
  }
47
47
  exports._percentile = _percentile;
48
+ /**
49
+ * A tiny bit more efficient function than calling _percentile individually.
50
+ */
51
+ function _percentiles(values, pcs) {
52
+ const r = {};
53
+ const sorted = (0, number_util_1._sortNumbers)(values);
54
+ pcs.forEach(pc => {
55
+ // Floating pos in the range of [0; length - 1]
56
+ const pos = ((values.length - 1) * pc) / 100;
57
+ const dec = pos % 1;
58
+ const floorPos = Math.floor(pos);
59
+ const ceilPos = Math.ceil(pos);
60
+ r[pc] = _averageWeighted([sorted[floorPos], sorted[ceilPos]], [1 - dec, dec]);
61
+ });
62
+ return r;
63
+ }
64
+ exports._percentiles = _percentiles;
48
65
  /**
49
66
  * @example
50
67
  *
@@ -35,6 +35,8 @@ export declare class NumberStack extends Stack<number> {
35
35
  * Returns null if Stack is empty.
36
36
  */
37
37
  avgOrNull(): number | null;
38
+ median(): number;
39
+ medianOrNull(): number | null;
38
40
  /**
39
41
  * `pc` is a number from 0 to 100 inclusive.
40
42
  */
@@ -44,6 +46,5 @@ export declare class NumberStack extends Stack<number> {
44
46
  * Returns null if Stack is empty.
45
47
  */
46
48
  percentileOrNull(pc: number): number | null;
47
- median(): number;
48
- medianOrNull(): number | null;
49
+ percentiles(pcs: number[]): Record<number, number>;
49
50
  }
@@ -60,6 +60,12 @@ class NumberStack extends Stack {
60
60
  avgOrNull() {
61
61
  return this.items.length === 0 ? null : (0, index_1._average)(this.items);
62
62
  }
63
+ median() {
64
+ return (0, index_1._percentile)(this.items, 50);
65
+ }
66
+ medianOrNull() {
67
+ return this.items.length === 0 ? null : (0, index_1._percentile)(this.items, 50);
68
+ }
63
69
  /**
64
70
  * `pc` is a number from 0 to 100 inclusive.
65
71
  */
@@ -74,11 +80,8 @@ class NumberStack extends Stack {
74
80
  percentileOrNull(pc) {
75
81
  return this.items.length === 0 ? null : (0, index_1._percentile)(this.items, pc);
76
82
  }
77
- median() {
78
- return (0, index_1._percentile)(this.items, 50);
79
- }
80
- medianOrNull() {
81
- return this.items.length === 0 ? null : (0, index_1._percentile)(this.items, 50);
83
+ percentiles(pcs) {
84
+ return (0, index_1._percentiles)(this.items, pcs);
82
85
  }
83
86
  }
84
87
  exports.NumberStack = NumberStack;
@@ -39,6 +39,22 @@ export function _percentile(values, pc) {
39
39
  const ceilPos = Math.ceil(pos);
40
40
  return _averageWeighted([sorted[floorPos], sorted[ceilPos]], [1 - dec, dec]);
41
41
  }
42
+ /**
43
+ * A tiny bit more efficient function than calling _percentile individually.
44
+ */
45
+ export function _percentiles(values, pcs) {
46
+ const r = {};
47
+ const sorted = _sortNumbers(values);
48
+ pcs.forEach(pc => {
49
+ // Floating pos in the range of [0; length - 1]
50
+ const pos = ((values.length - 1) * pc) / 100;
51
+ const dec = pos % 1;
52
+ const floorPos = Math.floor(pos);
53
+ const ceilPos = Math.ceil(pos);
54
+ r[pc] = _averageWeighted([sorted[floorPos], sorted[ceilPos]], [1 - dec, dec]);
55
+ });
56
+ return r;
57
+ }
42
58
  /**
43
59
  * @example
44
60
  *
@@ -1,4 +1,4 @@
1
- import { _average, _percentile, _range } from '../index';
1
+ import { _average, _percentile, _percentiles, _range } from '../index';
2
2
  /**
3
3
  * Implements a "round-robin" Stack ("first-in last-out" aka FILO) with a limited size.
4
4
  * Like an array of a fixed size. When it runs out of space - it starts writing on top of itself
@@ -56,6 +56,12 @@ export class NumberStack extends Stack {
56
56
  avgOrNull() {
57
57
  return this.items.length === 0 ? null : _average(this.items);
58
58
  }
59
+ median() {
60
+ return _percentile(this.items, 50);
61
+ }
62
+ medianOrNull() {
63
+ return this.items.length === 0 ? null : _percentile(this.items, 50);
64
+ }
59
65
  /**
60
66
  * `pc` is a number from 0 to 100 inclusive.
61
67
  */
@@ -70,10 +76,7 @@ export class NumberStack extends Stack {
70
76
  percentileOrNull(pc) {
71
77
  return this.items.length === 0 ? null : _percentile(this.items, pc);
72
78
  }
73
- median() {
74
- return _percentile(this.items, 50);
75
- }
76
- medianOrNull() {
77
- return this.items.length === 0 ? null : _percentile(this.items, 50);
79
+ percentiles(pcs) {
80
+ return _percentiles(this.items, pcs);
78
81
  }
79
82
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
- "version": "14.73.0",
3
+ "version": "14.74.0",
4
4
  "scripts": {
5
5
  "prepare": "husky install",
6
6
  "build-prod": "build-prod-esm-cjs",
@@ -47,6 +47,27 @@ export function _percentile(values: number[], pc: number): number {
47
47
  return _averageWeighted([sorted[floorPos]!, sorted[ceilPos]!], [1 - dec, dec])
48
48
  }
49
49
 
50
+ /**
51
+ * A tiny bit more efficient function than calling _percentile individually.
52
+ */
53
+ export function _percentiles(values: number[], pcs: number[]): Record<number, number> {
54
+ const r = {} as Record<number, number>
55
+
56
+ const sorted = _sortNumbers(values)
57
+
58
+ pcs.forEach(pc => {
59
+ // Floating pos in the range of [0; length - 1]
60
+ const pos = ((values.length - 1) * pc) / 100
61
+ const dec = pos % 1
62
+ const floorPos = Math.floor(pos)
63
+ const ceilPos = Math.ceil(pos)
64
+
65
+ r[pc] = _averageWeighted([sorted[floorPos]!, sorted[ceilPos]!], [1 - dec, dec])
66
+ })
67
+
68
+ return r
69
+ }
70
+
50
71
  /**
51
72
  * @example
52
73
  *
@@ -1,4 +1,4 @@
1
- import { _average, _percentile, _range } from '../index'
1
+ import { _average, _percentile, _percentiles, _range } from '../index'
2
2
 
3
3
  /**
4
4
  * Implements a "round-robin" Stack ("first-in last-out" aka FILO) with a limited size.
@@ -64,6 +64,14 @@ export class NumberStack extends Stack<number> {
64
64
  return this.items.length === 0 ? null : _average(this.items)
65
65
  }
66
66
 
67
+ median(): number {
68
+ return _percentile(this.items, 50)
69
+ }
70
+
71
+ medianOrNull(): number | null {
72
+ return this.items.length === 0 ? null : _percentile(this.items, 50)
73
+ }
74
+
67
75
  /**
68
76
  * `pc` is a number from 0 to 100 inclusive.
69
77
  */
@@ -80,11 +88,7 @@ export class NumberStack extends Stack<number> {
80
88
  return this.items.length === 0 ? null : _percentile(this.items, pc)
81
89
  }
82
90
 
83
- median(): number {
84
- return _percentile(this.items, 50)
85
- }
86
-
87
- medianOrNull(): number | null {
88
- return this.items.length === 0 ? null : _percentile(this.items, 50)
91
+ percentiles(pcs: number[]): Record<number, number> {
92
+ return _percentiles(this.items, pcs)
89
93
  }
90
94
  }