senaev-utils 1.0.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.
- package/README.md +11 -0
- package/package.json +66 -0
- package/src/reactHooks/setDeepEqualState.ts +19 -0
- package/src/reactHooks/useLocationParameter.ts +46 -0
- package/src/reactHooks/useObjectDeepChangesCounter.ts +22 -0
- package/src/reactHooks/useObservableMap/useObservableMap.ts +21 -0
- package/src/reactHooks/useRecentChangeTimer.ts +42 -0
- package/src/reactHooks/useReload.ts +17 -0
- package/src/reactHooks/useVisualizedProcessesTree.ts +202 -0
- package/src/types/Boolean.ts +9 -0
- package/src/types/DeepPartial.ts +1 -0
- package/src/types/GlobalContext.ts +8 -0
- package/src/types/HexColorString.ts +9 -0
- package/src/types/ISOLang.ts +5 -0
- package/src/types/IsEqualUnion.ts +1 -0
- package/src/types/IterableWithIndexAccess.ts +4 -0
- package/src/types/Kilobits.ts +4 -0
- package/src/types/Network/Bits.ts +4 -0
- package/src/types/Network/Bps.ts +4 -0
- package/src/types/Network/Kbps.ts +4 -0
- package/src/types/Network/Mbps.ts +4 -0
- package/src/types/Number/AngleInDegrees.ts +3 -0
- package/src/types/Number/FiniteNumber.ts +11 -0
- package/src/types/Number/Integer.ts +14 -0
- package/src/types/Number/IntegerInString.ts +13 -0
- package/src/types/Number/Number.ts +15 -0
- package/src/types/Number/Portion.ts +4 -0
- package/src/types/Number/PositiveInteger.ts +30 -0
- package/src/types/Number/PositiveNumber.ts +4 -0
- package/src/types/Number/StringUnsignedInteger.ts +4 -0
- package/src/types/Number/UnsignedFiniteNumber.ts +13 -0
- package/src/types/Number/UnsignedInteger.ts +28 -0
- package/src/types/Object/Object.ts +20 -0
- package/src/types/Percent.ts +4 -0
- package/src/types/PixelPosition.ts +9 -0
- package/src/types/PixelSize.ts +9 -0
- package/src/types/Pixels.ts +4 -0
- package/src/types/RangeTuple.ts +1 -0
- package/src/types/Size.ts +8 -0
- package/src/types/Time/DaysCount.ts +6 -0
- package/src/types/Time/Hours.ts +4 -0
- package/src/types/Time/ISODateString/ISODateString.ts +16 -0
- package/src/types/Time/Milliseconds.ts +4 -0
- package/src/types/Time/Minutes.ts +4 -0
- package/src/types/Time/Seconds.ts +5 -0
- package/src/types/Time/Time.ts +13 -0
- package/src/types/Time/Timestamp.ts +6 -0
- package/src/types/Time/UnixTimeMs.ts +6 -0
- package/src/types/Time/UnixTimeSec.ts +11 -0
- package/src/types/Time/const.ts +24 -0
- package/src/types/any/AnyAsyncFunction.ts +2 -0
- package/src/types/any/AnyFunction.ts +2 -0
- package/src/types/assertions/ANY_VALUE.ts +2 -0
- package/src/types/assertions/isNever/isNever.ts +34 -0
- package/src/types/assertions/isTrue/isTrue.ts +13 -0
- package/src/utils/AbortableProcess.ts +160 -0
- package/src/utils/Array/createArray/createArray.ts +8 -0
- package/src/utils/Array/createIntegerSequenceArray/createIntegerSequenceArray.ts +3 -0
- package/src/utils/Array/getUniqueValues/getUniqueValues.ts +3 -0
- package/src/utils/Array/separateToArrays/separateToArrays.ts +24 -0
- package/src/utils/Array/shuffleArray/shuffleArray.ts +18 -0
- package/src/utils/CircularBuffer/CircularBuffer.ts +117 -0
- package/src/utils/DOM/blurDocument.ts +3 -0
- package/src/utils/DOM/unfocusDocument.ts +3 -0
- package/src/utils/Date/dateToUnixTimeSec/dateToUnixTimeSec.ts +6 -0
- package/src/utils/Date/isoDateStringToUnixTimeMs/isoDateStringToUnixTimeMs.ts +6 -0
- package/src/utils/Date/isoDateStringToUnixTimeSec/isoDateStringToUnixTimeSec.ts +7 -0
- package/src/utils/Date/unixTimeSecToIsoDateString/unixTimeSecToIsoDateString.ts +6 -0
- package/src/utils/Deque/Deque.ts +530 -0
- package/src/utils/DeviceDetection/isTouchScreenDevice/isTouchScreenDevice.ts +16 -0
- package/src/utils/Error/rethrowError/rethrowError.ts +8 -0
- package/src/utils/Error/wrapError.ts +32 -0
- package/src/utils/Function/callFirstThenOther/callFirstThenOther.ts +24 -0
- package/src/utils/Function/callFunctions/callFunctions.ts +11 -0
- package/src/utils/Function/callTimes/callTimes.ts +5 -0
- package/src/utils/Function/isFunction.ts +3 -0
- package/src/utils/Function/noop/index.ts +4 -0
- package/src/utils/Function/once/once.ts +32 -0
- package/src/utils/Function/subscribeUpdatesWithTimeout/index.ts +44 -0
- package/src/utils/Function/throttleFunction/throttleFunction.ts +18 -0
- package/src/utils/Function/throttleWithPromiseFunction/throttleWithPromiseFunction.ts +19 -0
- package/src/utils/Function/tryCatch/tryCatch.ts +13 -0
- package/src/utils/Latch/Latch.ts +63 -0
- package/src/utils/Map/ObservableMap/ObservableMap.ts +55 -0
- package/src/utils/Map/findMapsDifferences/findMapsDifferences.ts +35 -0
- package/src/utils/Map/mapGetOrSet/mapGetOrSet.ts +7 -0
- package/src/utils/Map/mapMapToArray/mapMapToArray.ts +6 -0
- package/src/utils/Map/mapMapValues/mapMapValues.ts +9 -0
- package/src/utils/Math/createSimpleMovingAverageSeries/createSimpleMovingAverageSeries.ts +22 -0
- package/src/utils/Math/mean/mean.ts +14 -0
- package/src/utils/Math/simpleMovingAverageUsingAccFabric/simpleMovingAverageUsingAccFabric.ts +29 -0
- package/src/utils/Math/sum/sum.ts +45 -0
- package/src/utils/MinHeap/MinHeap.ts +88 -0
- package/src/utils/MinHeapUniqueNumber/MinHeapUniqueNumber.ts +105 -0
- package/src/utils/MinMaxHeap/MinMaxHeap.ts +91 -0
- package/src/utils/Number/collectIntegerSequences/collectIntegerSequences.ts +36 -0
- package/src/utils/Number/numberToFixedPrecision/numberToFixedPrecision.ts +13 -0
- package/src/utils/Object/cloneObject/cloneObject.ts +3 -0
- package/src/utils/Object/deepEqual/deepEqual.ts +45 -0
- package/src/utils/Object/deleteUndefinedProperties/index.ts +13 -0
- package/src/utils/Object/entriesToObject/entriesToObject.ts +12 -0
- package/src/utils/Object/filterObject/filterObject.ts +18 -0
- package/src/utils/Object/forOwn/forOwn.ts +12 -0
- package/src/utils/Object/getObjectEntries/getObjectEntries.ts +3 -0
- package/src/utils/Object/getObjectKeys/getObjectKeys.ts +3 -0
- package/src/utils/Object/getObjectValues/index.ts +3 -0
- package/src/utils/Object/hasOwnProperty/hasOwnProperty.ts +3 -0
- package/src/utils/Object/invertObject/InvertedObject.ts +3 -0
- package/src/utils/Object/invertObject/invertObject.ts +15 -0
- package/src/utils/Object/isEmptyObject/index.ts +5 -0
- package/src/utils/Object/isObject/index.ts +8 -0
- package/src/utils/Object/mapObjectKeys/mapObjectKeys.ts +25 -0
- package/src/utils/Object/mapObjectValues/mapObjectValues.ts +16 -0
- package/src/utils/Object/mirrorObject/ObjectKeysMirror.ts +1 -0
- package/src/utils/Object/mirrorObject/mirrorObject.ts +7 -0
- package/src/utils/Pagination/DEFAULT_PAGE.ts +1 -0
- package/src/utils/Pagination/calculatePaginationParameters.ts +29 -0
- package/src/utils/Promise/promiseAll/promiseAll.ts +6 -0
- package/src/utils/Promise/restrictParallelCalls/restrictParallelCalls.ts +18 -0
- package/src/utils/Ranges/checkRangesAdjacent/checkRangesAdjacent.ts +23 -0
- package/src/utils/Ranges/checkRangesIntersection/checkRangesIntersection.ts +8 -0
- package/src/utils/Ranges/excludeRanges/excludeRanges.ts +42 -0
- package/src/utils/Ranges/getDistanceToRange/getDistanceToRange.ts +14 -0
- package/src/utils/Ranges/isRangeWithinRanges.ts +14 -0
- package/src/utils/Ranges/mapDateRangeToISODateStringRange/mapDateRangeToISODateStringRange.ts +7 -0
- package/src/utils/Ranges/mapISODateStringRangeToUnixTimeMsRange/mapISODateStringRangeToUnixTimeMsRange.ts +8 -0
- package/src/utils/Ranges/mapRange/mapRange.ts +13 -0
- package/src/utils/Ranges/mapUnixTimeMsRangeToISODateStringRange/mapUnixTimeMsRangeToISODateStringRange.ts +8 -0
- package/src/utils/Ranges/mergeRanges/mergeRanges.ts +34 -0
- package/src/utils/Signal/Signal.ts +47 -0
- package/src/utils/Signal/SignalCallback.ts +1 -0
- package/src/utils/Signal/combineSignalsIntoNewOne/combineSignalsIntoNewOne.ts +75 -0
- package/src/utils/Signal/subscribeSignalAndCallWithCurrentValue/subscribeSignalAndCallWithCurrentValue.ts +7 -0
- package/src/utils/Signal/useSignal.ts +10 -0
- package/src/utils/String/HexString/HEX_SYMBOLS.ts +1 -0
- package/src/utils/String/HexString/HexString.ts +2 -0
- package/src/utils/String/HexString/isHexString.ts +16 -0
- package/src/utils/String/NonEmptyString/NonEmptyString.ts +22 -0
- package/src/utils/String/endsWith/index.ts +6 -0
- package/src/utils/String/isString.ts +3 -0
- package/src/utils/binarySearch/binarySearch.ts +20 -0
- package/src/utils/binarySearchClosest/binarySearchClosest.ts +43 -0
- package/src/utils/createIncrementalIntegerGenerator.ts +7 -0
- package/src/utils/createRemoteDataProcessingWindow/createRemoteDataProcessingWindow.ts +157 -0
- package/src/utils/createSimultaneousOperationsHandler/createSimultaneousOperationsHandler.ts +65 -0
- package/src/utils/encryptDecryptString/encryptDecryptString.ts +34 -0
- package/src/utils/getPrimeNumbersWithEratosthenesSieve/getPrimeNumbersWithEratosthenesSieve.ts +21 -0
- package/src/utils/isPromise/isPromise.ts +30 -0
- package/src/utils/makeAsyncFunctionCallsSimultaneous/makeAsyncFunctionCallsSimultaneous.ts +64 -0
- package/src/utils/parallelsLimitPromise/index.ts +28 -0
- package/src/utils/parallelsLimitQueue/parallelsLimitQueue.ts +69 -0
- package/src/utils/prettyStringify/index.ts +3 -0
- package/src/utils/random/fnv1a/fnv1a.ts +87 -0
- package/src/utils/random/generateHashedFloats/generateHashedFloats.ts +28 -0
- package/src/utils/random/getRandomIntegerInARange/getRandomIntegerInARange.ts +3 -0
- package/src/utils/random/getSampleIndexByStringHash/getSampleIndexByStringHash.ts +10 -0
- package/src/utils/random/randomBoolean/randomBoolean.ts +3 -0
- package/src/utils/random/randomHexString/randomHexString.ts +12 -0
- package/src/utils/requestAnimationFrame/requestAnimationFramePromise/requestAnimationFramePromise.ts +7 -0
- package/src/utils/requestAnimationFrame/requestAnimationFrameThrottle/requestAnimationFrameThrottle.ts +6 -0
- package/src/utils/retryFunctionWrapper/retryFunctionWrapper.ts +40 -0
- package/src/utils/runParallelTimescalesProcessing/runParallelTimescalesProcessing.ts +113 -0
- package/src/utils/stringifyError.ts +3 -0
- package/src/utils/timers/promiseTimeout/promiseTimeout.ts +26 -0
- package/src/utils/timers/subscribeSyntheticInterval/subscribeSyntheticInterval.ts +47 -0
- package/src/utils/waitForFunction/waitForFunction.ts +50 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Milliseconds } from '../../../types/Time/Milliseconds';
|
|
2
|
+
import { noop } from '../noop';
|
|
3
|
+
|
|
4
|
+
export function subscribeUpdatesWithTimeout<T> ({
|
|
5
|
+
callback,
|
|
6
|
+
subscribe,
|
|
7
|
+
timeout,
|
|
8
|
+
onResubscribe,
|
|
9
|
+
}: {
|
|
10
|
+
callback: (value: T) => void;
|
|
11
|
+
subscribe: (cb: typeof callback) => VoidFunction;
|
|
12
|
+
timeout: Milliseconds;
|
|
13
|
+
onResubscribe: VoidFunction;
|
|
14
|
+
}): void {
|
|
15
|
+
let refreshTimeoutId: ReturnType<typeof setTimeout>;
|
|
16
|
+
const clearResubscribeTimeout = () => {
|
|
17
|
+
clearTimeout(refreshTimeoutId);
|
|
18
|
+
};
|
|
19
|
+
const setResubscribeTimeout = () => {
|
|
20
|
+
refreshTimeoutId = setTimeout(resubscribe, timeout);
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
let unsubscribe = noop;
|
|
24
|
+
const resubscribe = (isFirst = false) => {
|
|
25
|
+
if (!isFirst) {
|
|
26
|
+
onResubscribe();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
clearResubscribeTimeout();
|
|
30
|
+
unsubscribe();
|
|
31
|
+
|
|
32
|
+
unsubscribe = subscribe((value) => {
|
|
33
|
+
clearResubscribeTimeout();
|
|
34
|
+
|
|
35
|
+
callback(value);
|
|
36
|
+
|
|
37
|
+
setResubscribeTimeout();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
setResubscribeTimeout();
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
resubscribe(true);
|
|
44
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Subject, throttleTime } from 'rxjs';
|
|
2
|
+
|
|
3
|
+
import { Milliseconds } from '../../../types/Time/Milliseconds';
|
|
4
|
+
|
|
5
|
+
export function throttleFunction(func: VoidFunction, delay: Milliseconds): VoidFunction {
|
|
6
|
+
const subject = new Subject();
|
|
7
|
+
|
|
8
|
+
subject
|
|
9
|
+
.pipe(throttleTime(delay, undefined, {
|
|
10
|
+
leading: true,
|
|
11
|
+
trailing: true,
|
|
12
|
+
}))
|
|
13
|
+
.subscribe(func);
|
|
14
|
+
|
|
15
|
+
return () => {
|
|
16
|
+
subject.next(undefined);
|
|
17
|
+
};
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function throttleWithPromiseFunction(callback: VoidFunction, promiseFunction: () => Promise<void>) {
|
|
2
|
+
let isRunning = false;
|
|
3
|
+
|
|
4
|
+
const throttled = () => {
|
|
5
|
+
if (isRunning) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
isRunning = true;
|
|
10
|
+
|
|
11
|
+
promiseFunction().finally(() => {
|
|
12
|
+
callback();
|
|
13
|
+
|
|
14
|
+
isRunning = false;
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
return throttled;
|
|
19
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { AnyFunction } from '../../../types/any/AnyFunction';
|
|
2
|
+
|
|
3
|
+
export function tryCatch<T extends AnyFunction>(fn: T, onError?: (e: Error) => void): ReturnType<T> | undefined {
|
|
4
|
+
try {
|
|
5
|
+
return fn();
|
|
6
|
+
} catch (e) {
|
|
7
|
+
if (typeof onError === 'function') {
|
|
8
|
+
onError(e as Error);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { callFunctions } from '../Function/callFunctions/callFunctions';
|
|
2
|
+
import { isFunction } from '../Function/isFunction';
|
|
3
|
+
import { noop } from '../Function/noop';
|
|
4
|
+
import { once } from '../Function/once/once';
|
|
5
|
+
|
|
6
|
+
export type LatchCallback<T> = (parameter: T) => void;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Класс, инстанс которого хранит неизменяемое значение и может находиться в двух состояниях
|
|
10
|
+
* - значение не задано
|
|
11
|
+
* - значение задано
|
|
12
|
+
*
|
|
13
|
+
* Если значение не задано, подписаться на его установку можно с помощью метода subscribe,
|
|
14
|
+
* а установить значение вызвав метод dispatch
|
|
15
|
+
*
|
|
16
|
+
* В случае, если значение задано, при вызове метода subscribe callback отрабатывает сразу,
|
|
17
|
+
* а дальнейшие вызовы dispatch игнорируются
|
|
18
|
+
*/
|
|
19
|
+
export class Latch<T = undefined> {
|
|
20
|
+
public dispatch = once((value: T): void => {
|
|
21
|
+
this.value = value;
|
|
22
|
+
this._isDispatched = true;
|
|
23
|
+
|
|
24
|
+
callFunctions(this.callbacks, value);
|
|
25
|
+
this.callbacks.clear();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
private readonly callbacks: Set<LatchCallback<T>> = new Set();
|
|
29
|
+
private _isDispatched = false;
|
|
30
|
+
private value?: T;
|
|
31
|
+
|
|
32
|
+
public constructor(callback?: LatchCallback<T>) {
|
|
33
|
+
if (isFunction(callback)) {
|
|
34
|
+
this.callbacks.add(callback);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public subscribe(callback: LatchCallback<T>): VoidFunction {
|
|
39
|
+
if (this._isDispatched) {
|
|
40
|
+
callback(this.value!);
|
|
41
|
+
|
|
42
|
+
return noop;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
this.callbacks.add(callback);
|
|
46
|
+
|
|
47
|
+
return () => {
|
|
48
|
+
this.callbacks.delete(callback);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public unsubscribe(callback: LatchCallback<T>): void {
|
|
53
|
+
this.callbacks.delete(callback);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public isDispatched(): boolean {
|
|
57
|
+
return this._isDispatched;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public getValue(): T | undefined {
|
|
61
|
+
return this.value;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { callFunctions } from '../../Function/callFunctions/callFunctions';
|
|
2
|
+
|
|
3
|
+
type ObservableMapEvent<K, V> =
|
|
4
|
+
| {
|
|
5
|
+
type: 'set';
|
|
6
|
+
key: K;
|
|
7
|
+
value: V;
|
|
8
|
+
}
|
|
9
|
+
| {
|
|
10
|
+
type: 'delete';
|
|
11
|
+
key: K;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type ObservableMapCallback<K, V> = (event: ObservableMapEvent<K, V>) => void;
|
|
15
|
+
|
|
16
|
+
export class ObservableMap<K, V> extends Map<K, V> {
|
|
17
|
+
private readonly _callbacks: Set<ObservableMapCallback<K, V>> = new Set();
|
|
18
|
+
|
|
19
|
+
public subscribe(callback: ObservableMapCallback<K, V>): VoidFunction {
|
|
20
|
+
this._callbacks.add(callback);
|
|
21
|
+
|
|
22
|
+
return () => {
|
|
23
|
+
this._callbacks.delete(callback);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public set (key: K, value: V): this {
|
|
28
|
+
const previousValue = this.get(key);
|
|
29
|
+
|
|
30
|
+
super.set(key, value);
|
|
31
|
+
|
|
32
|
+
if (value !== previousValue) {
|
|
33
|
+
callFunctions(this._callbacks ?? [], {
|
|
34
|
+
type: 'set',
|
|
35
|
+
key,
|
|
36
|
+
value,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public delete (key: K): boolean {
|
|
44
|
+
const result = super.delete(key);
|
|
45
|
+
|
|
46
|
+
if (result) {
|
|
47
|
+
callFunctions(this._callbacks ?? [], {
|
|
48
|
+
type: 'delete',
|
|
49
|
+
key,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function findMapsDifferences<K, V, V2>(originalMap: Map<K, V>, targetMap: Map<K, V2>): {
|
|
2
|
+
added: K[];
|
|
3
|
+
updated: K[];
|
|
4
|
+
deleted: K[];
|
|
5
|
+
} {
|
|
6
|
+
const result = {
|
|
7
|
+
added: [] as K[],
|
|
8
|
+
updated: [] as K[],
|
|
9
|
+
deleted: [] as K[],
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// Value added to the original map
|
|
13
|
+
targetMap.forEach((_, id) => {
|
|
14
|
+
if (!originalMap.has(id)) {
|
|
15
|
+
result.added.push(id);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
originalMap.forEach((_, id) => {
|
|
20
|
+
if (targetMap.has(id)) {
|
|
21
|
+
const originalValue = originalMap.get(id);
|
|
22
|
+
const targetValue = targetMap.get(id);
|
|
23
|
+
|
|
24
|
+
// Value has been changed
|
|
25
|
+
if (originalValue !== targetValue) {
|
|
26
|
+
result.updated.push(id);
|
|
27
|
+
}
|
|
28
|
+
} else {
|
|
29
|
+
// Value is not represented in settings anymore
|
|
30
|
+
result.deleted.push(id);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { PositiveInteger } from '../../../types/Number/PositiveInteger';
|
|
2
|
+
import { mean } from '../mean/mean';
|
|
3
|
+
|
|
4
|
+
export function createSimpleMovingAverageSeries({
|
|
5
|
+
series,
|
|
6
|
+
windowSize,
|
|
7
|
+
}: {
|
|
8
|
+
series: number[];
|
|
9
|
+
windowSize: PositiveInteger;
|
|
10
|
+
}): (number | undefined)[] {
|
|
11
|
+
const movingAverageData: (number | undefined)[] = [];
|
|
12
|
+
|
|
13
|
+
for (let i = 0; i < series.length; i++) {
|
|
14
|
+
if (i < windowSize - 1) {
|
|
15
|
+
movingAverageData.push(undefined);
|
|
16
|
+
} else {
|
|
17
|
+
movingAverageData.push(mean(series.slice(i - windowSize + 1, i + 1)));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return movingAverageData;
|
|
22
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { IterableWithIndexAccess } from '../../../types/IterableWithIndexAccess';
|
|
2
|
+
import { sum } from '../sum/sum';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Stolen from here
|
|
6
|
+
* https://github.com/simple-statistics/simple-statistics/blob/ac07cbec74534a4b4c71a541292e9ae8c26f0930/src/mean.js#L17C1-L23C2
|
|
7
|
+
*/
|
|
8
|
+
export function mean(x: IterableWithIndexAccess<number>): number {
|
|
9
|
+
if (x.length === 0) {
|
|
10
|
+
throw new Error('mean requires at least one data point');
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return sum(x) / x.length;
|
|
14
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { PositiveInteger } from '../../../types/Number/PositiveInteger';
|
|
2
|
+
import { CircularBuffer } from '../../CircularBuffer/CircularBuffer';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Calculates using accumulator to avoid re-calculating the mean
|
|
6
|
+
* Can have small floating point errors
|
|
7
|
+
*/
|
|
8
|
+
export function simpleMovingAverageUsingAccFabric(windowSize: PositiveInteger): (value: number) => number | undefined {
|
|
9
|
+
const queue = new CircularBuffer<number>(windowSize);
|
|
10
|
+
let accumulator = 0;
|
|
11
|
+
|
|
12
|
+
return (newValue: number) => {
|
|
13
|
+
let diff = newValue;
|
|
14
|
+
|
|
15
|
+
if (queue.length === windowSize) {
|
|
16
|
+
diff -= queue.shift()!;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
queue.push(newValue);
|
|
20
|
+
|
|
21
|
+
accumulator += diff / windowSize;
|
|
22
|
+
|
|
23
|
+
if (queue.length < windowSize) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return accumulator;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { IterableWithIndexAccess } from '../../../types/IterableWithIndexAccess';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stolen from here
|
|
5
|
+
* https://github.com/simple-statistics/simple-statistics/blob/ac07cbec74534a4b4c71a541292e9ae8c26f0930/src/sum.js#L19C1-L56C2
|
|
6
|
+
*/
|
|
7
|
+
export function sum(x: IterableWithIndexAccess<number>): number {
|
|
8
|
+
// If the array is empty, we needn't bother computing its sum
|
|
9
|
+
if (x.length === 0) {
|
|
10
|
+
return 0;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Initializing the sum as the first number in the array
|
|
14
|
+
let sumResult = x.at(0);
|
|
15
|
+
|
|
16
|
+
// Keeping track of the floating-point error correction
|
|
17
|
+
let correction: number = 0;
|
|
18
|
+
|
|
19
|
+
let transition: number;
|
|
20
|
+
|
|
21
|
+
if (typeof sumResult !== 'number') {
|
|
22
|
+
return Number.NaN;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
for (let i = 1; i < x.length; i++) {
|
|
26
|
+
if (typeof x.at(i) !== 'number') {
|
|
27
|
+
return Number.NaN;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
transition = sumResult + x.at(i)!;
|
|
31
|
+
|
|
32
|
+
// Here we need to update the correction in a different fashion
|
|
33
|
+
// if the new absolute value is greater than the absolute sum
|
|
34
|
+
if (Math.abs(sumResult) >= Math.abs(x.at(i)!)) {
|
|
35
|
+
correction += sumResult - transition + x.at(i)!;
|
|
36
|
+
} else {
|
|
37
|
+
correction += x.at(i)! - transition + sumResult;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
sumResult = transition;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Returning the corrected sum
|
|
44
|
+
return sumResult + correction;
|
|
45
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export type MinHeapTuple<T> = [number, T];
|
|
2
|
+
|
|
3
|
+
export class MinHeap<T> {
|
|
4
|
+
private _heap: MinHeapTuple<T>[];
|
|
5
|
+
|
|
6
|
+
public constructor() {
|
|
7
|
+
this._heap = [];
|
|
8
|
+
}
|
|
9
|
+
public push(value: MinHeapTuple<T>): void {
|
|
10
|
+
this._heap.push(value);
|
|
11
|
+
this._bubbleUp();
|
|
12
|
+
}
|
|
13
|
+
public getFirst(): MinHeapTuple<T> | undefined {
|
|
14
|
+
return this._heap[0];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public getSize(): number {
|
|
18
|
+
return this._heap.length;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public pop(): MinHeapTuple<T> | undefined {
|
|
22
|
+
if (this._heap.length <= 1) {
|
|
23
|
+
return this._heap.pop();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const top = this._heap[0];
|
|
27
|
+
|
|
28
|
+
this._heap[0] = this._heap.pop()!;
|
|
29
|
+
this._bubbleDown();
|
|
30
|
+
|
|
31
|
+
return top;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private _bubbleUp(): void {
|
|
35
|
+
let idx = this._heap.length - 1;
|
|
36
|
+
|
|
37
|
+
while (idx > 0) {
|
|
38
|
+
const parentIdx = Math.floor((idx - 1) / 2);
|
|
39
|
+
const current = this._heap[idx];
|
|
40
|
+
const parent = this._heap[parentIdx];
|
|
41
|
+
|
|
42
|
+
if (parent[0] <= current[0]) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
this._heap[idx] = parent;
|
|
47
|
+
this._heap[parentIdx] = current;
|
|
48
|
+
|
|
49
|
+
idx = parentIdx;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private _bubbleDown(): void {
|
|
54
|
+
let idx = 0;
|
|
55
|
+
|
|
56
|
+
while (true) {
|
|
57
|
+
const leftIdx = 2 * idx + 1;
|
|
58
|
+
const rightIdx = 2 * idx + 2;
|
|
59
|
+
|
|
60
|
+
if (leftIdx >= this._heap.length) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let smallestIdx = leftIdx;
|
|
65
|
+
const hasRight = rightIdx < this._heap.length;
|
|
66
|
+
|
|
67
|
+
if (hasRight) {
|
|
68
|
+
const rightIsPrior = this._heap[rightIdx][0] < this._heap[leftIdx][0];
|
|
69
|
+
|
|
70
|
+
if (rightIsPrior) {
|
|
71
|
+
smallestIdx = rightIdx;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const value = this._heap[idx];
|
|
76
|
+
const smallestValue = this._heap[smallestIdx];
|
|
77
|
+
|
|
78
|
+
if (value[0] <= smallestValue[0]) {
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
this._heap[idx] = smallestValue;
|
|
83
|
+
this._heap[smallestIdx] = value;
|
|
84
|
+
|
|
85
|
+
idx = smallestIdx;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
export class MinHeapUniqueNumber {
|
|
2
|
+
private readonly _heap: number[];
|
|
3
|
+
private readonly _set: Set<number> = new Set();
|
|
4
|
+
|
|
5
|
+
public constructor() {
|
|
6
|
+
this._heap = [];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
public push(value: number): void {
|
|
10
|
+
if (this._set.has(value)) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
this._set.add(value);
|
|
15
|
+
|
|
16
|
+
this._heap.push(value);
|
|
17
|
+
this._bubbleUp();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public getFirst(): number | undefined {
|
|
21
|
+
return this._heap[0];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public getSize(): number {
|
|
25
|
+
return this._heap.length;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
public pop(): number | undefined {
|
|
29
|
+
if (this._heap.length === 0) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (this._heap.length <= 1) {
|
|
34
|
+
const value = this._heap.pop()!;
|
|
35
|
+
|
|
36
|
+
this._set.delete(value);
|
|
37
|
+
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const top = this._heap[0];
|
|
42
|
+
|
|
43
|
+
this._heap[0] = this._heap.pop()!;
|
|
44
|
+
this._bubbleDown();
|
|
45
|
+
|
|
46
|
+
this._set.delete(top);
|
|
47
|
+
|
|
48
|
+
return top;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private _bubbleUp(): void {
|
|
52
|
+
let idx = this._heap.length - 1;
|
|
53
|
+
|
|
54
|
+
while (idx > 0) {
|
|
55
|
+
const parentIdx = Math.floor((idx - 1) / 2);
|
|
56
|
+
const current = this._heap[idx];
|
|
57
|
+
const parent = this._heap[parentIdx];
|
|
58
|
+
|
|
59
|
+
if (parent < current) {
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this._heap[idx] = parent;
|
|
64
|
+
this._heap[parentIdx] = current;
|
|
65
|
+
|
|
66
|
+
idx = parentIdx;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private _bubbleDown(): void {
|
|
71
|
+
let idx = 0;
|
|
72
|
+
|
|
73
|
+
while (true) {
|
|
74
|
+
const leftIdx = 2 * idx + 1;
|
|
75
|
+
const rightIdx = 2 * idx + 2;
|
|
76
|
+
|
|
77
|
+
if (leftIdx >= this._heap.length) {
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let smallestIdx = leftIdx;
|
|
82
|
+
const hasRight = rightIdx < this._heap.length;
|
|
83
|
+
|
|
84
|
+
if (hasRight) {
|
|
85
|
+
const rightIsPrior = this._heap[rightIdx] < this._heap[leftIdx];
|
|
86
|
+
|
|
87
|
+
if (rightIsPrior) {
|
|
88
|
+
smallestIdx = rightIdx;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const value = this._heap[idx];
|
|
93
|
+
const smallestValue = this._heap[smallestIdx];
|
|
94
|
+
|
|
95
|
+
if (value < smallestValue) {
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
this._heap[idx] = smallestValue;
|
|
100
|
+
this._heap[smallestIdx] = value;
|
|
101
|
+
|
|
102
|
+
idx = smallestIdx;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
export type MinMaxHeapTuple<T> = [number, T];
|
|
2
|
+
export type MinMaxHeapCompareFunction = (a: number, b: number) => number;
|
|
3
|
+
|
|
4
|
+
export class MinMaxHeap<T> {
|
|
5
|
+
private _heap: MinMaxHeapTuple<T>[];
|
|
6
|
+
private _compare: MinMaxHeapCompareFunction;
|
|
7
|
+
|
|
8
|
+
public constructor(compare: MinMaxHeapCompareFunction) {
|
|
9
|
+
this._heap = [];
|
|
10
|
+
this._compare = compare;
|
|
11
|
+
}
|
|
12
|
+
public push(value: MinMaxHeapTuple<T>): void {
|
|
13
|
+
this._heap.push(value);
|
|
14
|
+
this._bubbleUp();
|
|
15
|
+
}
|
|
16
|
+
public getFirst(): MinMaxHeapTuple<T> | undefined {
|
|
17
|
+
return this._heap[0];
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public getSize(): number {
|
|
21
|
+
return this._heap.length;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public pop(): MinMaxHeapTuple<T> | undefined {
|
|
25
|
+
if (this._heap.length <= 1) {
|
|
26
|
+
return this._heap.pop();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const top = this._heap[0];
|
|
30
|
+
|
|
31
|
+
this._heap[0] = this._heap.pop()!;
|
|
32
|
+
this._bubbleDown();
|
|
33
|
+
|
|
34
|
+
return top;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
private _bubbleUp(): void {
|
|
38
|
+
let idx = this._heap.length - 1;
|
|
39
|
+
|
|
40
|
+
while (idx > 0) {
|
|
41
|
+
const parentIdx = Math.floor((idx - 1) / 2);
|
|
42
|
+
const current = this._heap[idx];
|
|
43
|
+
const parent = this._heap[parentIdx];
|
|
44
|
+
|
|
45
|
+
if (this._compare(parent[0], current[0]) < 0) {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this._heap[idx] = parent;
|
|
50
|
+
this._heap[parentIdx] = current;
|
|
51
|
+
|
|
52
|
+
idx = parentIdx;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private _bubbleDown(): void {
|
|
57
|
+
let idx = 0;
|
|
58
|
+
|
|
59
|
+
while (true) {
|
|
60
|
+
const leftIdx = 2 * idx + 1;
|
|
61
|
+
const rightIdx = 2 * idx + 2;
|
|
62
|
+
|
|
63
|
+
if (leftIdx >= this._heap.length) {
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let smallestIdx = leftIdx;
|
|
68
|
+
const hasRight = rightIdx < this._heap.length;
|
|
69
|
+
|
|
70
|
+
if (hasRight) {
|
|
71
|
+
const rightIsPrior = this._compare(this._heap[rightIdx][0], this._heap[leftIdx][0]) < 0;
|
|
72
|
+
|
|
73
|
+
if (rightIsPrior) {
|
|
74
|
+
smallestIdx = rightIdx;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const value = this._heap[idx];
|
|
79
|
+
const smallestValue = this._heap[smallestIdx];
|
|
80
|
+
|
|
81
|
+
if (this._compare(value[0], smallestValue[0]) < 0) {
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
this._heap[idx] = smallestValue;
|
|
86
|
+
this._heap[smallestIdx] = value;
|
|
87
|
+
|
|
88
|
+
idx = smallestIdx;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|