oakscriptjs 0.9.4 → 0.9.6
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.
- package/dist/cjs/array/index.d.ts +88 -27
- package/dist/cjs/array/index.d.ts.map +1 -1
- package/dist/cjs/array/index.js +257 -117
- package/dist/cjs/array/index.js.map +3 -3
- package/dist/cjs/callsite/index.d.ts +122 -4
- package/dist/cjs/callsite/index.d.ts.map +1 -1
- package/dist/cjs/callsite/index.js +102 -3
- package/dist/cjs/callsite/index.js.map +2 -2
- package/dist/cjs/color/index.d.ts +7 -3
- package/dist/cjs/color/index.d.ts.map +1 -1
- package/dist/cjs/color/index.js +6 -1
- package/dist/cjs/color/index.js.map +2 -2
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/label/index.d.ts.map +1 -1
- package/dist/cjs/label/index.js +2 -1
- package/dist/cjs/label/index.js.map +2 -2
- package/dist/cjs/linefill/index.d.ts.map +1 -1
- package/dist/cjs/linefill/index.js +1 -0
- package/dist/cjs/linefill/index.js.map +2 -2
- package/dist/cjs/math/index.d.ts +79 -22
- package/dist/cjs/math/index.d.ts.map +1 -1
- package/dist/cjs/math/index.js +157 -43
- package/dist/cjs/math/index.js.map +3 -3
- package/dist/cjs/matrix/index.d.ts.map +1 -1
- package/dist/cjs/matrix/index.js +42 -36
- package/dist/cjs/matrix/index.js.map +2 -2
- package/dist/cjs/runtime/series.d.ts +9 -0
- package/dist/cjs/runtime/series.d.ts.map +1 -1
- package/dist/cjs/runtime/series.js +16 -2
- package/dist/cjs/runtime/series.js.map +2 -2
- package/dist/cjs/script/index.d.ts +15 -31
- package/dist/cjs/script/index.d.ts.map +1 -1
- package/dist/cjs/script/index.js +32 -0
- package/dist/cjs/script/index.js.map +2 -2
- package/dist/cjs/session/calendar.d.ts.map +1 -1
- package/dist/cjs/session/calendar.js +15 -2
- package/dist/cjs/session/calendar.js.map +2 -2
- package/dist/cjs/str/index.d.ts +50 -38
- package/dist/cjs/str/index.d.ts.map +1 -1
- package/dist/cjs/str/index.js +43 -15
- package/dist/cjs/str/index.js.map +2 -2
- package/dist/cjs/str/messageformat.d.ts +2 -1
- package/dist/cjs/str/messageformat.d.ts.map +1 -1
- package/dist/cjs/str/messageformat.js +4 -1
- package/dist/cjs/str/messageformat.js.map +2 -2
- package/dist/cjs/str/numberformat.d.ts +4 -0
- package/dist/cjs/str/numberformat.d.ts.map +1 -1
- package/dist/cjs/str/numberformat.js +26 -4
- package/dist/cjs/str/numberformat.js.map +3 -3
- package/dist/cjs/ta/index.d.ts +95 -46
- package/dist/cjs/ta/index.d.ts.map +1 -1
- package/dist/cjs/ta/index.js +193 -318
- package/dist/cjs/ta/index.js.map +3 -3
- package/dist/cjs/ta/running-sum.d.ts +54 -1
- package/dist/cjs/ta/running-sum.d.ts.map +1 -1
- package/dist/cjs/ta/running-sum.js +132 -47
- package/dist/cjs/ta/running-sum.js.map +2 -2
- package/dist/cjs/ta-series.d.ts +4 -4
- package/dist/cjs/ta-series.d.ts.map +1 -1
- package/dist/cjs/ta-series.js +4 -3
- package/dist/cjs/ta-series.js.map +2 -2
- package/dist/cjs/time/datestring.d.ts +1 -0
- package/dist/cjs/time/datestring.d.ts.map +1 -1
- package/dist/cjs/time/datestring.js +7 -0
- package/dist/cjs/time/datestring.js.map +2 -2
- package/dist/cjs/time/index.d.ts.map +1 -1
- package/dist/cjs/time/index.js +2 -1
- package/dist/cjs/time/index.js.map +2 -2
- package/dist/cjs/time/session.d.ts +28 -9
- package/dist/cjs/time/session.d.ts.map +1 -1
- package/dist/cjs/time/session.js +74 -28
- package/dist/cjs/time/session.js.map +2 -2
- package/dist/cjs/time/timezone.d.ts +5 -0
- package/dist/cjs/time/timezone.d.ts.map +1 -1
- package/dist/cjs/time/timezone.js +15 -1
- package/dist/cjs/time/timezone.js.map +2 -2
- package/dist/esm/array/index.d.ts +88 -27
- package/dist/esm/array/index.d.ts.map +1 -1
- package/dist/esm/array/index.js +408 -157
- package/dist/esm/array/index.js.map +1 -1
- package/dist/esm/callsite/index.d.ts +122 -4
- package/dist/esm/callsite/index.d.ts.map +1 -1
- package/dist/esm/callsite/index.js +228 -8
- package/dist/esm/callsite/index.js.map +1 -1
- package/dist/esm/color/index.d.ts +7 -3
- package/dist/esm/color/index.d.ts.map +1 -1
- package/dist/esm/color/index.js +15 -3
- package/dist/esm/color/index.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/label/index.d.ts.map +1 -1
- package/dist/esm/label/index.js +2 -1
- package/dist/esm/label/index.js.map +1 -1
- package/dist/esm/linefill/index.d.ts.map +1 -1
- package/dist/esm/linefill/index.js +3 -0
- package/dist/esm/linefill/index.js.map +1 -1
- package/dist/esm/math/index.d.ts +79 -22
- package/dist/esm/math/index.d.ts.map +1 -1
- package/dist/esm/math/index.js +229 -63
- package/dist/esm/math/index.js.map +1 -1
- package/dist/esm/matrix/index.d.ts.map +1 -1
- package/dist/esm/matrix/index.js +57 -43
- package/dist/esm/matrix/index.js.map +1 -1
- package/dist/esm/runtime/series.d.ts +9 -0
- package/dist/esm/runtime/series.d.ts.map +1 -1
- package/dist/esm/runtime/series.js +18 -1
- package/dist/esm/runtime/series.js.map +1 -1
- package/dist/esm/script/index.d.ts +15 -31
- package/dist/esm/script/index.d.ts.map +1 -1
- package/dist/esm/script/index.js +44 -1
- package/dist/esm/script/index.js.map +1 -1
- package/dist/esm/session/calendar.d.ts.map +1 -1
- package/dist/esm/session/calendar.js +22 -2
- package/dist/esm/session/calendar.js.map +1 -1
- package/dist/esm/str/index.d.ts +50 -38
- package/dist/esm/str/index.d.ts.map +1 -1
- package/dist/esm/str/index.js +103 -52
- package/dist/esm/str/index.js.map +1 -1
- package/dist/esm/str/messageformat.d.ts +2 -1
- package/dist/esm/str/messageformat.d.ts.map +1 -1
- package/dist/esm/str/messageformat.js +7 -2
- package/dist/esm/str/messageformat.js.map +1 -1
- package/dist/esm/str/numberformat.d.ts +4 -0
- package/dist/esm/str/numberformat.d.ts.map +1 -1
- package/dist/esm/str/numberformat.js +38 -4
- package/dist/esm/str/numberformat.js.map +1 -1
- package/dist/esm/ta/index.d.ts +95 -46
- package/dist/esm/ta/index.d.ts.map +1 -1
- package/dist/esm/ta/index.js +341 -414
- package/dist/esm/ta/index.js.map +1 -1
- package/dist/esm/ta/running-sum.d.ts +54 -1
- package/dist/esm/ta/running-sum.d.ts.map +1 -1
- package/dist/esm/ta/running-sum.js +166 -60
- package/dist/esm/ta/running-sum.js.map +1 -1
- package/dist/esm/ta-series.d.ts +4 -4
- package/dist/esm/ta-series.d.ts.map +1 -1
- package/dist/esm/ta-series.js +5 -4
- package/dist/esm/ta-series.js.map +1 -1
- package/dist/esm/time/datestring.d.ts +1 -0
- package/dist/esm/time/datestring.d.ts.map +1 -1
- package/dist/esm/time/datestring.js +12 -0
- package/dist/esm/time/datestring.js.map +1 -1
- package/dist/esm/time/index.d.ts.map +1 -1
- package/dist/esm/time/index.js +3 -1
- package/dist/esm/time/index.js.map +1 -1
- package/dist/esm/time/session.d.ts +28 -9
- package/dist/esm/time/session.d.ts.map +1 -1
- package/dist/esm/time/session.js +113 -42
- package/dist/esm/time/session.js.map +1 -1
- package/dist/esm/time/timezone.d.ts +5 -0
- package/dist/esm/time/timezone.d.ts.map +1 -1
- package/dist/esm/time/timezone.js +21 -1
- package/dist/esm/time/timezone.js.map +1 -1
- package/package.json +2 -2
- package/src/array/index.ts +382 -174
- package/src/callsite/index.ts +232 -8
- package/src/color/index.ts +15 -5
- package/src/index.ts +1 -1
- package/src/label/index.ts +2 -1
- package/src/linefill/index.ts +2 -0
- package/src/math/index.ts +261 -77
- package/src/matrix/index.ts +52 -52
- package/src/runtime/series.ts +22 -1
- package/src/script/index.ts +53 -1
- package/src/session/calendar.ts +22 -2
- package/src/str/index.ts +95 -51
- package/src/str/messageformat.ts +7 -2
- package/src/str/numberformat.ts +39 -4
- package/src/ta/index.ts +356 -458
- package/src/ta/running-sum.ts +187 -62
- package/src/ta-series.ts +8 -7
- package/src/time/datestring.ts +10 -0
- package/src/time/index.ts +3 -1
- package/src/time/session.ts +97 -47
- package/src/time/timezone.ts +21 -1
package/dist/cjs/array/index.js
CHANGED
|
@@ -85,11 +85,27 @@ function new_array(size2 = 0, initial_value) {
|
|
|
85
85
|
function size(id) {
|
|
86
86
|
return id.length;
|
|
87
87
|
}
|
|
88
|
+
function isNa(v) {
|
|
89
|
+
return v === void 0 || v === null || typeof v === "number" && Number.isNaN(v);
|
|
90
|
+
}
|
|
91
|
+
function naOf(id) {
|
|
92
|
+
return id.length === 0 || typeof id[0] === "number" ? NaN : void 0;
|
|
93
|
+
}
|
|
94
|
+
function position(name, id, index, extra = 0) {
|
|
95
|
+
const i = Math.trunc(index);
|
|
96
|
+
const n = id.length;
|
|
97
|
+
if (i < -n || i >= n + extra) {
|
|
98
|
+
throw new Error(`array.${name}: index ${i} is out of bounds, array size is ${n}`);
|
|
99
|
+
}
|
|
100
|
+
return i < 0 ? i + n : i;
|
|
101
|
+
}
|
|
88
102
|
function get(id, index) {
|
|
89
|
-
return id
|
|
103
|
+
if (Number.isNaN(index)) return naOf(id);
|
|
104
|
+
return id[position("get", id, index)];
|
|
90
105
|
}
|
|
91
106
|
function set(id, index, value) {
|
|
92
|
-
|
|
107
|
+
if (Number.isNaN(index)) return;
|
|
108
|
+
id[position("set", id, index)] = value;
|
|
93
109
|
}
|
|
94
110
|
function push(id, value) {
|
|
95
111
|
id.push(value);
|
|
@@ -107,25 +123,46 @@ function clear(id) {
|
|
|
107
123
|
id.length = 0;
|
|
108
124
|
}
|
|
109
125
|
function insert(id, index, value) {
|
|
110
|
-
|
|
126
|
+
if (Number.isNaN(index)) {
|
|
127
|
+
id.push(value);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
id.splice(position("insert", id, index, 1), 0, value);
|
|
111
131
|
}
|
|
112
132
|
function remove(id, index) {
|
|
113
|
-
|
|
133
|
+
if (Number.isNaN(index)) return naOf(id);
|
|
134
|
+
return id.splice(position("remove", id, index), 1)[0];
|
|
135
|
+
}
|
|
136
|
+
function pineEqual(a, b) {
|
|
137
|
+
if (isNa(a) || isNa(b)) return false;
|
|
138
|
+
if (a === b) return true;
|
|
139
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
140
|
+
const d = a - b;
|
|
141
|
+
return -1e-10 <= d && d <= 1e-10;
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
114
144
|
}
|
|
115
145
|
function includes(id, value) {
|
|
116
|
-
return id
|
|
146
|
+
return indexof(id, value) >= 0;
|
|
117
147
|
}
|
|
118
148
|
function indexof(id, value) {
|
|
119
|
-
|
|
149
|
+
for (let i = 0; i < id.length; i++) {
|
|
150
|
+
if (pineEqual(id[i], value)) return i;
|
|
151
|
+
}
|
|
152
|
+
return -1;
|
|
120
153
|
}
|
|
121
154
|
function lastindexof(id, value) {
|
|
122
|
-
|
|
155
|
+
for (let i = id.length - 1; i >= 0; i--) {
|
|
156
|
+
if (pineEqual(id[i], value)) return i;
|
|
157
|
+
}
|
|
158
|
+
return -1;
|
|
123
159
|
}
|
|
124
160
|
function copy(id) {
|
|
125
161
|
return [...id];
|
|
126
162
|
}
|
|
127
163
|
function concat(id1, id2) {
|
|
128
|
-
|
|
164
|
+
for (const v of Array.from(id2)) id1.push(v);
|
|
165
|
+
return id1;
|
|
129
166
|
}
|
|
130
167
|
function join(id, separator = ",") {
|
|
131
168
|
return id.join(separator);
|
|
@@ -134,64 +171,162 @@ function reverse(id) {
|
|
|
134
171
|
id.reverse();
|
|
135
172
|
}
|
|
136
173
|
function slice(id, index_from, index_to) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
174
|
+
const n = id.length;
|
|
175
|
+
const start = Number.isNaN(index_from) ? 0 : Math.trunc(index_from);
|
|
176
|
+
const stop = index_to === void 0 || Number.isNaN(index_to) ? n : Math.trunc(index_to);
|
|
177
|
+
if (start < 0 || start >= n) throw new Error(`array.slice: index ${start} is out of bounds, array size is ${n}`);
|
|
178
|
+
if (stop < 0 || stop > n) throw new Error(`array.slice: index ${stop} is out of bounds, array size is ${n}`);
|
|
179
|
+
if (start > stop) throw new Error(`array.slice: index_from ${start} is greater than index_to ${stop}`);
|
|
180
|
+
return sliceView(id, start, stop - start);
|
|
181
|
+
}
|
|
182
|
+
function indexKey(p) {
|
|
183
|
+
if (typeof p !== "string") return -1;
|
|
184
|
+
const i = Number(p);
|
|
185
|
+
return Number.isInteger(i) && i >= 0 && String(i) === p ? i : -1;
|
|
186
|
+
}
|
|
187
|
+
function sliceView(parent, start, size2) {
|
|
188
|
+
const resize = (target) => {
|
|
189
|
+
if (target > size2) parent.splice(start + size2, 0, ...Array(target - size2).fill(void 0));
|
|
190
|
+
else if (target < size2) parent.splice(start + target, size2 - target);
|
|
191
|
+
size2 = target;
|
|
192
|
+
};
|
|
193
|
+
return new Proxy([], {
|
|
194
|
+
get(target, p, receiver) {
|
|
195
|
+
const i = indexKey(p);
|
|
196
|
+
if (i >= 0) return i < size2 ? parent[start + i] : void 0;
|
|
197
|
+
if (p === "length") return size2;
|
|
198
|
+
return Reflect.get(target, p, receiver);
|
|
199
|
+
},
|
|
200
|
+
set(target, p, value, receiver) {
|
|
201
|
+
const i = indexKey(p);
|
|
202
|
+
if (i >= 0) {
|
|
203
|
+
if (i >= size2) resize(i + 1);
|
|
204
|
+
parent[start + i] = value;
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
if (p === "length") {
|
|
208
|
+
resize(Number(value));
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
return Reflect.set(target, p, value, receiver);
|
|
212
|
+
},
|
|
213
|
+
has(target, p) {
|
|
214
|
+
const i = indexKey(p);
|
|
215
|
+
return i >= 0 ? i < size2 : Reflect.has(target, p);
|
|
216
|
+
},
|
|
217
|
+
// Array methods delete the slots past the new end before they set the length, which does the removal.
|
|
218
|
+
deleteProperty(target, p) {
|
|
219
|
+
return indexKey(p) >= 0 ? true : Reflect.deleteProperty(target, p);
|
|
220
|
+
},
|
|
221
|
+
ownKeys(target) {
|
|
222
|
+
return [...Array.from({ length: size2 }, (_, i) => String(i)), ...Reflect.ownKeys(target)];
|
|
223
|
+
},
|
|
224
|
+
getOwnPropertyDescriptor(target, p) {
|
|
225
|
+
const i = indexKey(p);
|
|
226
|
+
if (i >= 0) {
|
|
227
|
+
return i < size2 ? { value: parent[start + i], writable: true, enumerable: true, configurable: true } : void 0;
|
|
228
|
+
}
|
|
229
|
+
if (p === "length") return { value: size2, writable: true, enumerable: false, configurable: false };
|
|
230
|
+
return Reflect.getOwnPropertyDescriptor(target, p);
|
|
145
231
|
}
|
|
146
232
|
});
|
|
147
233
|
}
|
|
234
|
+
function sortedPositions(id, order) {
|
|
235
|
+
const values = [];
|
|
236
|
+
const nas = [];
|
|
237
|
+
for (let i = 0; i < id.length; i++) (isNa(id[i]) ? nas : values).push(i);
|
|
238
|
+
values.sort((a, b) => {
|
|
239
|
+
const x = id[a];
|
|
240
|
+
const y = id[b];
|
|
241
|
+
return x < y ? -1 : x > y ? 1 : 0;
|
|
242
|
+
});
|
|
243
|
+
const naFirst = values.length > 0 && typeof id[values[0]] === "string";
|
|
244
|
+
const positions = naFirst ? [...nas, ...values] : [...values, ...nas];
|
|
245
|
+
if (order === "desc" || order === "descending") positions.reverse();
|
|
246
|
+
return positions;
|
|
247
|
+
}
|
|
248
|
+
function sort(id, order = "asc") {
|
|
249
|
+
const sorted = sortedPositions(id, order).map((p) => id[p]);
|
|
250
|
+
for (let i = 0; i < sorted.length; i++) id[i] = sorted[i];
|
|
251
|
+
}
|
|
148
252
|
function sum(id) {
|
|
149
|
-
|
|
253
|
+
let total = 0;
|
|
254
|
+
let count = 0;
|
|
255
|
+
for (const v of id) {
|
|
256
|
+
if (Number.isNaN(v)) continue;
|
|
257
|
+
count++;
|
|
258
|
+
total += v;
|
|
259
|
+
if (Math.abs(total) <= 1e-10) total = 0;
|
|
260
|
+
}
|
|
261
|
+
return count ? total : NaN;
|
|
150
262
|
}
|
|
151
263
|
function avg(id) {
|
|
152
264
|
const values = id.filter((v) => !Number.isNaN(v));
|
|
153
265
|
return values.length ? values.reduce((a, b) => a + b, 0) / values.length : NaN;
|
|
154
266
|
}
|
|
267
|
+
function nthValue(name, id, nth, compare) {
|
|
268
|
+
const rank = Number.isNaN(nth) ? 0 : Math.trunc(nth);
|
|
269
|
+
const values = id.filter((v) => !Number.isNaN(v));
|
|
270
|
+
if (!values.length) return NaN;
|
|
271
|
+
if (rank < 0 || rank >= id.length) {
|
|
272
|
+
throw new Error(`array.${name}: nth ${rank} is out of bounds, array size is ${id.length}`);
|
|
273
|
+
}
|
|
274
|
+
values.sort(compare);
|
|
275
|
+
return values[Math.min(rank, values.length - 1)];
|
|
276
|
+
}
|
|
155
277
|
function min(id, nth = 0) {
|
|
156
|
-
|
|
157
|
-
return values.length ? values[Math.min(nth, values.length - 1)] : NaN;
|
|
278
|
+
return nthValue("min", id, nth, (a, b) => a - b);
|
|
158
279
|
}
|
|
159
280
|
function max(id, nth = 0) {
|
|
160
|
-
|
|
161
|
-
return values.length ? values[Math.min(nth, values.length - 1)] : NaN;
|
|
281
|
+
return nthValue("max", id, nth, (a, b) => b - a);
|
|
162
282
|
}
|
|
163
283
|
function median(id) {
|
|
164
|
-
const sorted =
|
|
284
|
+
const sorted = id.filter((v) => !Number.isNaN(v)).sort((a, b) => a - b);
|
|
285
|
+
if (!sorted.length) return NaN;
|
|
165
286
|
const mid = Math.floor(sorted.length / 2);
|
|
166
287
|
return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
|
|
167
288
|
}
|
|
168
289
|
function mode(id) {
|
|
169
290
|
const frequency = /* @__PURE__ */ new Map();
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
291
|
+
for (const v of id) {
|
|
292
|
+
if (!Number.isNaN(v)) frequency.set(v, (frequency.get(v) ?? 0) + 1);
|
|
293
|
+
}
|
|
294
|
+
let best = NaN;
|
|
295
|
+
let bestCount = 0;
|
|
296
|
+
for (const [v, count] of frequency) {
|
|
297
|
+
if (count > bestCount || count === bestCount && v < best) {
|
|
298
|
+
best = v;
|
|
299
|
+
bestCount = count;
|
|
178
300
|
}
|
|
179
301
|
}
|
|
180
|
-
return
|
|
302
|
+
return best;
|
|
181
303
|
}
|
|
182
304
|
function stdev(id, biased = true) {
|
|
183
305
|
return Math.sqrt(variance(id, biased));
|
|
184
306
|
}
|
|
307
|
+
function moments(values) {
|
|
308
|
+
let p = 0;
|
|
309
|
+
let q = 0;
|
|
310
|
+
for (const v of values) p += v;
|
|
311
|
+
for (const v of values) q += v * v;
|
|
312
|
+
return [p, q];
|
|
313
|
+
}
|
|
185
314
|
function variance(id, biased = true) {
|
|
186
315
|
const values = id.filter((v) => !Number.isNaN(v));
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
316
|
+
const n = values.length;
|
|
317
|
+
if (!n) return NaN;
|
|
318
|
+
if (n < 2) return biased ? 0 : NaN;
|
|
319
|
+
const [p, q] = moments(values);
|
|
320
|
+
const mean = p / n;
|
|
321
|
+
return biased ? Math.max(0, q / n - mean * mean) : Math.max(0, q / (n - 1) - p / (n - 1) * mean);
|
|
191
322
|
}
|
|
192
323
|
function fill(id, value, index_from = 0, index_to) {
|
|
193
|
-
const
|
|
194
|
-
|
|
324
|
+
const start = index_from === void 0 || index_from === null || Number.isNaN(index_from) ? 0 : index_from;
|
|
325
|
+
const end = index_to === void 0 || index_to === null || Number.isNaN(index_to) ? id.length : index_to;
|
|
326
|
+
for (const i of [start, end]) {
|
|
327
|
+
if (i < 0 || i > id.length) throw new Error(`array.fill: index ${i} is out of bounds, array size is ${id.length}`);
|
|
328
|
+
}
|
|
329
|
+
for (let i = start; i < end; i++) {
|
|
195
330
|
id[i] = value;
|
|
196
331
|
}
|
|
197
332
|
}
|
|
@@ -199,9 +334,11 @@ function from(...values) {
|
|
|
199
334
|
return [...values];
|
|
200
335
|
}
|
|
201
336
|
function first(id) {
|
|
337
|
+
if (id.length === 0) throw new Error("Cannot call array.first() if array is empty");
|
|
202
338
|
return id[0];
|
|
203
339
|
}
|
|
204
340
|
function last(id) {
|
|
341
|
+
if (id.length === 0) throw new Error("Cannot call array.last() if array is empty");
|
|
205
342
|
return id[id.length - 1];
|
|
206
343
|
}
|
|
207
344
|
function some(id) {
|
|
@@ -263,129 +400,132 @@ function binary_search(id, val) {
|
|
|
263
400
|
return -1;
|
|
264
401
|
}
|
|
265
402
|
function binary_search_leftmost(id, val) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
403
|
+
if (id.length === 0) return -1;
|
|
404
|
+
const at = searchBound(id, val, false);
|
|
405
|
+
return at < id.length && compareSorted(id[at], val) === 0 ? at : Math.max(0, at - 1);
|
|
406
|
+
}
|
|
407
|
+
function compareSorted(a, b) {
|
|
408
|
+
const an = Number.isNaN(a);
|
|
409
|
+
const bn = Number.isNaN(b);
|
|
410
|
+
if (an || bn) return an === bn ? 0 : an ? 1 : -1;
|
|
411
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
412
|
+
}
|
|
413
|
+
function searchBound(id, val, after) {
|
|
414
|
+
let lo = 0;
|
|
415
|
+
let hi = id.length;
|
|
416
|
+
while (lo < hi) {
|
|
417
|
+
const mid = lo + hi >>> 1;
|
|
418
|
+
const c = compareSorted(id[mid], val);
|
|
419
|
+
if (c < 0 || after && c === 0) lo = mid + 1;
|
|
420
|
+
else hi = mid;
|
|
284
421
|
}
|
|
285
|
-
return
|
|
422
|
+
return lo;
|
|
286
423
|
}
|
|
287
424
|
function binary_search_rightmost(id, val) {
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
let found = false;
|
|
292
|
-
while (left <= right) {
|
|
293
|
-
const mid = Math.floor((left + right) / 2);
|
|
294
|
-
if (id[mid] <= val) {
|
|
295
|
-
if (id[mid] === val) {
|
|
296
|
-
result = mid;
|
|
297
|
-
found = true;
|
|
298
|
-
}
|
|
299
|
-
left = mid + 1;
|
|
300
|
-
} else {
|
|
301
|
-
if (!found) {
|
|
302
|
-
result = mid;
|
|
303
|
-
}
|
|
304
|
-
right = mid - 1;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
return result;
|
|
425
|
+
if (id.length === 0) return -1;
|
|
426
|
+
const at = searchBound(id, val, true);
|
|
427
|
+
return at > 0 && compareSorted(id[at - 1], val) === 0 ? at - 1 : at;
|
|
308
428
|
}
|
|
309
429
|
function covariance(id1, id2, biased = true) {
|
|
310
|
-
if (id1.length === 0 || id2.length === 0) {
|
|
311
|
-
return NaN;
|
|
312
|
-
}
|
|
313
430
|
if (id1.length !== id2.length) {
|
|
314
431
|
return NaN;
|
|
315
432
|
}
|
|
316
|
-
const
|
|
317
|
-
const
|
|
318
|
-
|
|
433
|
+
const xs = [];
|
|
434
|
+
const ys = [];
|
|
435
|
+
for (let i = 0; i < id1.length; i++) {
|
|
436
|
+
if (Number.isNaN(id1[i]) || Number.isNaN(id2[i])) continue;
|
|
437
|
+
xs.push(id1[i]);
|
|
438
|
+
ys.push(id2[i]);
|
|
439
|
+
}
|
|
440
|
+
const n = xs.length;
|
|
441
|
+
if (!n || !biased && n < 2) return NaN;
|
|
442
|
+
let mean1 = 0;
|
|
443
|
+
let mean2 = 0;
|
|
444
|
+
for (let i = 0; i < n; i++) {
|
|
445
|
+
mean1 += xs[i];
|
|
446
|
+
mean2 += ys[i];
|
|
447
|
+
}
|
|
448
|
+
mean1 /= n;
|
|
449
|
+
mean2 /= n;
|
|
319
450
|
let sum2 = 0;
|
|
320
451
|
for (let i = 0; i < n; i++) {
|
|
321
|
-
sum2 += (
|
|
452
|
+
sum2 += (xs[i] - mean1) * (ys[i] - mean2);
|
|
322
453
|
}
|
|
323
|
-
|
|
324
|
-
return sum2 / divisor;
|
|
454
|
+
return sum2 / (biased ? n : n - 1);
|
|
325
455
|
}
|
|
326
456
|
function percentile_linear_interpolation(id, percentage) {
|
|
327
|
-
if (id.length === 0) {
|
|
457
|
+
if (id.length === 0 || Number.isNaN(percentage)) {
|
|
328
458
|
return NaN;
|
|
329
459
|
}
|
|
460
|
+
checkPercentage("percentile_linear_interpolation", percentage);
|
|
330
461
|
const s = sortedNaLast(id);
|
|
331
462
|
const n = s.length;
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
if (pos
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
463
|
+
let pos = n * percentage / 100 + 0.5;
|
|
464
|
+
const nearest = Math.round(pos);
|
|
465
|
+
if (Math.abs(pos - nearest) < 1e-9) pos = nearest;
|
|
466
|
+
if (pos <= 1) return s[0];
|
|
467
|
+
if (pos >= n) return s[n - 1];
|
|
468
|
+
const lower = Math.floor(pos);
|
|
469
|
+
const frac = pos - lower;
|
|
470
|
+
if (frac === 0) return s[lower - 1];
|
|
471
|
+
if (Number.isNaN(s[n - 1])) return NaN;
|
|
472
|
+
return s[lower - 1] * (1 - frac) + s[lower] * frac;
|
|
339
473
|
}
|
|
340
474
|
function sortedNaLast(id) {
|
|
341
475
|
const numbers = id.filter((v) => !Number.isNaN(v)).sort((a, b) => a - b);
|
|
342
476
|
return [...numbers, ...Array(id.length - numbers.length).fill(NaN)];
|
|
343
477
|
}
|
|
478
|
+
function checkPercentage(name, percentage) {
|
|
479
|
+
if (!(percentage >= 0 && percentage <= 100)) {
|
|
480
|
+
throw new Error(`array.${name}: percentage ${percentage} must be between 0 and 100`);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
344
483
|
function percentile_nearest_rank(id, percentage) {
|
|
345
484
|
if (id.length === 0) {
|
|
346
485
|
return NaN;
|
|
347
486
|
}
|
|
487
|
+
const pct = Number.isNaN(percentage) ? 0 : percentage;
|
|
488
|
+
checkPercentage("percentile_nearest_rank", pct);
|
|
348
489
|
const s = sortedNaLast(id);
|
|
349
|
-
const rank = Math.min(s.length, Math.max(1, Math.ceil(
|
|
490
|
+
const rank = Math.min(s.length, Math.max(1, Math.ceil(pct * s.length / 100)));
|
|
350
491
|
return s[rank - 1];
|
|
351
492
|
}
|
|
352
493
|
function percentrank(id, index) {
|
|
353
|
-
|
|
494
|
+
const i = Number.isNaN(index) ? 0 : Math.trunc(index);
|
|
495
|
+
if (id.length === 0) {
|
|
496
|
+
return NaN;
|
|
497
|
+
}
|
|
498
|
+
if (i < 0 || i >= id.length) {
|
|
499
|
+
throw new Error(`array.percentrank: index ${i} is out of bounds, array size is ${id.length}`);
|
|
500
|
+
}
|
|
501
|
+
if (id.length === 1) {
|
|
354
502
|
return NaN;
|
|
355
503
|
}
|
|
356
|
-
const value = id[
|
|
357
|
-
if (isNaN(value)) {
|
|
504
|
+
const value = id[i];
|
|
505
|
+
if (Number.isNaN(value)) {
|
|
358
506
|
return NaN;
|
|
359
507
|
}
|
|
360
508
|
let count = 0;
|
|
361
|
-
for (
|
|
362
|
-
if (
|
|
363
|
-
count++;
|
|
364
|
-
}
|
|
509
|
+
for (const v of id) {
|
|
510
|
+
if (v <= value) count++;
|
|
365
511
|
}
|
|
366
|
-
return count / id.length
|
|
512
|
+
return (count - 1) * 100 / (id.length - 1);
|
|
367
513
|
}
|
|
368
514
|
function sort_indices(id, order = "asc") {
|
|
369
|
-
|
|
370
|
-
indices.sort((a, b) => {
|
|
371
|
-
if (order === "asc") {
|
|
372
|
-
return id[a] - id[b];
|
|
373
|
-
} else {
|
|
374
|
-
return id[b] - id[a];
|
|
375
|
-
}
|
|
376
|
-
});
|
|
377
|
-
return indices;
|
|
515
|
+
return sortedPositions(id, order);
|
|
378
516
|
}
|
|
379
517
|
function standardize(id) {
|
|
380
|
-
|
|
381
|
-
|
|
518
|
+
const values = id.filter((v) => !Number.isNaN(v));
|
|
519
|
+
if (!values.length) {
|
|
520
|
+
return id.map(() => NaN);
|
|
382
521
|
}
|
|
383
|
-
const
|
|
384
|
-
const
|
|
522
|
+
const [p, q] = moments(values);
|
|
523
|
+
const mean = p / values.length;
|
|
524
|
+
const stdDev = Math.sqrt(Math.max(0, q / values.length - mean * mean));
|
|
385
525
|
if (stdDev === 0) {
|
|
386
|
-
return id.map(() => NaN);
|
|
526
|
+
return id.map((v) => Number.isNaN(v) ? NaN : 1);
|
|
387
527
|
}
|
|
388
|
-
return id.map((
|
|
528
|
+
return id.map((v) => Number.isNaN(v) ? NaN : (v - mean) / stdDev);
|
|
389
529
|
}
|
|
390
530
|
function newtype(size2 = 0, initial_value) {
|
|
391
531
|
return new_array(size2, initial_value);
|