@zoodogood/utils 3.0.0-change.2568 → 4.2.0-change.3344
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/lib/discordjs/simplify.d.ts +1 -1
- package/lib/objectives/BusyNumeric.d.ts +2 -0
- package/lib/objectives/BusyNumeric.js +26 -25
- package/lib/objectives/LazySort/LazySort.build.d.ts +52 -0
- package/lib/objectives/LazySort/LazySort.build.js +231 -0
- package/lib/objectives/LazySort/LazySort.test.d.ts +1 -0
- package/lib/objectives/LazySort/LazySort.test.js +69 -0
- package/lib/objectives/getRandomElementFromArray.d.ts +6 -2
- package/lib/objectives/getRandomElementFromArray.js +44 -31
- package/lib/primitives/BracketsParser.js +5 -0
- package/lib/primitives/CliParser.d.ts +1 -1
- package/lib/primitives/CliParser.js +15 -10
- package/lib/primitives/binary_search.d.ts +8 -0
- package/lib/primitives/binary_search.js +3 -0
- package/lib/primitives/normalize.d.ts +1 -1
- package/lib/primitives/normalize.js +6 -4
- package/package.json +2 -2
|
@@ -44,7 +44,7 @@ export function CreateModal({ title, customId, components }: {
|
|
|
44
44
|
title: any;
|
|
45
45
|
customId: any;
|
|
46
46
|
components: any;
|
|
47
|
-
}): import("discord.
|
|
47
|
+
}): import(".pnpm/discord-api-types@0.37.97/node_modules/discord-api-types/v10").APIModalInteractionResponseCallbackData;
|
|
48
48
|
export function SimplifyComponents(data: any): any;
|
|
49
49
|
/**
|
|
50
50
|
*
|
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
* 2) Хотя у нас есть список занятых номеров, у нас не может быть списка свободных (за условием задачи)
|
|
7
7
|
* Этот алгоритм используется для эффективного поиска тех самых свободных номеров, которые удовлетворяют заданному условию
|
|
8
8
|
*/
|
|
9
|
+
export declare function size_of_area(area: readonly [number, number]): number;
|
|
9
10
|
export declare class BusyNumeric {
|
|
10
11
|
#private;
|
|
11
12
|
readonly range: number;
|
|
12
13
|
readonly busy_areas: (readonly [number, number])[];
|
|
14
|
+
free_area: number;
|
|
13
15
|
get peak_start_busy(): boolean;
|
|
14
16
|
get peak_end_busy(): boolean;
|
|
15
17
|
constructor(range: number);
|
|
@@ -26,6 +26,7 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
26
26
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
27
27
|
};
|
|
28
28
|
var _BusyNumeric_peak_start_busy, _BusyNumeric_peak_end_busy;
|
|
29
|
+
import assert from "node:assert";
|
|
29
30
|
import { binary_search } from "../primitives/binary_search.js";
|
|
30
31
|
/**
|
|
31
32
|
* MARK: Представьте отель
|
|
@@ -39,6 +40,9 @@ import { binary_search } from "../primitives/binary_search.js";
|
|
|
39
40
|
// Если основное количество производительности не реализуется из-за особенностей структуры списка, то это можно оптимизировать
|
|
40
41
|
// Интересно что ветки дерева можно определять по индексу. Да, это интересное замечание.
|
|
41
42
|
// В BusyNumeric можно добавить ещё метод separate
|
|
43
|
+
export function size_of_area(area) {
|
|
44
|
+
return area[1] - area[0] + 1;
|
|
45
|
+
}
|
|
42
46
|
export class BusyNumeric {
|
|
43
47
|
get peak_start_busy() {
|
|
44
48
|
var _a;
|
|
@@ -77,10 +81,9 @@ export class BusyNumeric {
|
|
|
77
81
|
this.refresh._peak();
|
|
78
82
|
},
|
|
79
83
|
};
|
|
80
|
-
|
|
81
|
-
throw new Error("Assertion: range must be positive");
|
|
82
|
-
}
|
|
84
|
+
assert(range > 0, "Range must be positive");
|
|
83
85
|
this.range = range;
|
|
86
|
+
this.free_area = this.range + /* includes position 0 */ 1;
|
|
84
87
|
}
|
|
85
88
|
bifurcate(point) {
|
|
86
89
|
this.insert_area(point, point);
|
|
@@ -118,34 +121,32 @@ export class BusyNumeric {
|
|
|
118
121
|
return { size, left, right };
|
|
119
122
|
}
|
|
120
123
|
insert_area(start, end) {
|
|
121
|
-
|
|
122
|
-
throw new Error(`Assertion error: start or end not integer ${start} ${end}, maybe float?`);
|
|
123
|
-
}
|
|
124
|
+
assert(Number.isInteger(start) && Number.isInteger(end), `Assertion error: start or end not integer ${start} ${end}, maybe float?`);
|
|
124
125
|
if (start > end) {
|
|
125
126
|
[start, end] = [end, start];
|
|
126
127
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
return (+(((_c = (_b = this.busy_areas[index + 1]) === null || _b === void 0 ? void 0 : _b[1]) !== null && _c !== void 0 ? _c : Number.MAX_SAFE_INTEGER) > end) - 1);
|
|
141
|
-
}) + 1;
|
|
128
|
+
assert(start >= 0);
|
|
129
|
+
assert(end <= this.range);
|
|
130
|
+
const place_index = this.busy_areas.length
|
|
131
|
+
? binary_search(this.busy_areas.length - 1, (index) => {
|
|
132
|
+
var _a, _b, _c;
|
|
133
|
+
const value = (_a = this.busy_areas[index]) === null || _a === void 0 ? void 0 : _a[1];
|
|
134
|
+
const biggest = end < value;
|
|
135
|
+
if (biggest) {
|
|
136
|
+
return 1 /* BinarySearchCompareSpec.Biggest */;
|
|
137
|
+
}
|
|
138
|
+
return (+(((_c = (_b = this.busy_areas[index + 1]) === null || _b === void 0 ? void 0 : _b[1]) !== null && _c !== void 0 ? _c : Number.MAX_SAFE_INTEGER) > end) - 1);
|
|
139
|
+
}) + 1
|
|
140
|
+
: 0;
|
|
142
141
|
const left = this.busy_areas[place_index - 1];
|
|
143
142
|
const right = this.busy_areas[place_index];
|
|
144
143
|
const is_left_included = !!left && left[1] + 1 >= start;
|
|
145
144
|
const is_right_included = !!right && right[0] - 1 <= end;
|
|
146
145
|
// Merge strategy 3
|
|
147
146
|
if (is_left_included && is_right_included) {
|
|
148
|
-
|
|
147
|
+
const points = [left[0], right[1]];
|
|
148
|
+
this.free_area -= size_of_area(points) - size_of_area(left) - size_of_area(right);
|
|
149
|
+
this.busy_areas.splice(place_index - 1, 2, points);
|
|
149
150
|
return;
|
|
150
151
|
}
|
|
151
152
|
// Merge strategy 2
|
|
@@ -154,13 +155,13 @@ export class BusyNumeric {
|
|
|
154
155
|
const [index, points] = is_left_included
|
|
155
156
|
? [place_index - 1, [target[0], end]]
|
|
156
157
|
: [place_index, [start, target[1]]];
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
158
|
+
assert(!(target[0] <= start && target[1] >= end), "Assertion error: [start, end] in range");
|
|
159
|
+
this.free_area -= size_of_area(points) - size_of_area(target);
|
|
160
160
|
this.busy_areas.splice(index, 1, points);
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
163
163
|
// Merge strategy 1
|
|
164
|
+
this.free_area -= size_of_area([start, end]);
|
|
164
165
|
this.busy_areas.splice(place_index, 0, [start, end]);
|
|
165
166
|
}
|
|
166
167
|
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
type Predicate<T> = (T: T, index: number, array: T[]) => boolean;
|
|
2
|
+
export declare const enum ArrayEmulateStrategy {
|
|
3
|
+
Partial = 0,
|
|
4
|
+
Proxied = 1
|
|
5
|
+
}
|
|
6
|
+
interface Configuration {
|
|
7
|
+
chunks_count?: number;
|
|
8
|
+
revert?: boolean;
|
|
9
|
+
emulate?: ArrayEmulateStrategy;
|
|
10
|
+
}
|
|
11
|
+
type Chunk<T> = LazySort<T>;
|
|
12
|
+
type WithValue<T> = [T, number];
|
|
13
|
+
export declare class LazySort<T> {
|
|
14
|
+
#private;
|
|
15
|
+
emulate: ArrayEmulateStrategy;
|
|
16
|
+
revert: boolean;
|
|
17
|
+
chunks_count: number;
|
|
18
|
+
iterable: WithValue<T>[];
|
|
19
|
+
length: number;
|
|
20
|
+
calculated: boolean;
|
|
21
|
+
is_atomic?: boolean;
|
|
22
|
+
max?: number;
|
|
23
|
+
min?: number;
|
|
24
|
+
chunk_range?: number;
|
|
25
|
+
chunks?: Chunk<T>[];
|
|
26
|
+
chunk_thresholds?: number[];
|
|
27
|
+
static ofNumbers(numbers: number[]): LazySort<number>;
|
|
28
|
+
static ofArrayMapValue<T>(array: T[], valueOf: (T: T, index: number, arr: T[]) => T): LazySort<T>;
|
|
29
|
+
constructor(iterable1: WithValue<T>[], { revert: revert1, chunks_count: chunks_count1, emulate: emulate1 }?: Configuration);
|
|
30
|
+
get atomic_chunk_arr(): WithValue<T>[];
|
|
31
|
+
chunks_update_thresholds_after(chunk_index: number, diff: number): number[];
|
|
32
|
+
entry(): LazySortEntry<T>;
|
|
33
|
+
}
|
|
34
|
+
export declare class LazySortEntry<T> extends Array {
|
|
35
|
+
#private;
|
|
36
|
+
constructor(source: LazySort<T>);
|
|
37
|
+
entry(): this;
|
|
38
|
+
get length(): number;
|
|
39
|
+
set length(value: number);
|
|
40
|
+
[Symbol.iterator](): Generator<WithValue<T>>;
|
|
41
|
+
toArray(): WithValue<T>[];
|
|
42
|
+
positive_at(at: number): (WithValue<T> | undefined);
|
|
43
|
+
find(predicate: Predicate<WithValue<T>>): WithValue<T> | undefined;
|
|
44
|
+
findIndex(predicate: Predicate<WithValue<T>>): number;
|
|
45
|
+
findLast(predicate: Predicate<WithValue<T>>): WithValue<T> | undefined;
|
|
46
|
+
findIndexLast(predicate: Predicate<WithValue<T>>): number;
|
|
47
|
+
indexOf(item: WithValue<T>): number;
|
|
48
|
+
some(predicate: Predicate<WithValue<T>>): boolean;
|
|
49
|
+
every(predicate: Predicate<WithValue<T>>): boolean;
|
|
50
|
+
splice(start: number, deleteCount: number, ...items: WithValue<T>[]): WithValue<T>[];
|
|
51
|
+
}
|
|
52
|
+
export {};
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
// Декларации:
|
|
2
|
+
// Утверждаю: Атомик всегда отсортирован
|
|
3
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
|
4
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
5
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
6
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
7
|
+
};
|
|
8
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
9
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
10
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
11
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
12
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
13
|
+
};
|
|
14
|
+
var _LazySort_instances, _LazySort_to_proxied_array_emulator, _LazySort_to_partial_array_emulator, _LazySortEntry_source;
|
|
15
|
+
var concatAssign = (lhs, rhs) => { var _a; return (((_a = rhs === null || rhs === void 0 ? void 0 : rhs[Symbol.isConcatSpreadable]) !== null && _a !== void 0 ? _a : Array.isArray(rhs)) ? lhs.push.apply(lhs, rhs) : lhs.push(rhs), lhs); };
|
|
16
|
+
import assert from "node:assert";
|
|
17
|
+
const GOOD_CHUNKS_COUNT = 11;
|
|
18
|
+
export class LazySort {
|
|
19
|
+
static ofNumbers(numbers) {
|
|
20
|
+
return new this(numbers.map($1 => [$1, $1]));
|
|
21
|
+
}
|
|
22
|
+
static ofArrayMapValue(array, valueOf) {
|
|
23
|
+
return new this(array.map(($, i, arr) => [$, valueOf($, i, arr)]));
|
|
24
|
+
}
|
|
25
|
+
constructor(iterable1, { revert: revert1 = false, chunks_count: chunks_count1 = GOOD_CHUNKS_COUNT, emulate: emulate1 = 0 /* ArrayEmulateStrategy.Partial */ } = {}) {
|
|
26
|
+
_LazySort_instances.add(this);
|
|
27
|
+
this.calculated = false;
|
|
28
|
+
this.iterable = iterable1;
|
|
29
|
+
this.revert = revert1;
|
|
30
|
+
this.chunks_count = chunks_count1;
|
|
31
|
+
this.emulate = emulate1;
|
|
32
|
+
assert(this.chunks_count >= 2);
|
|
33
|
+
this.length = this.iterable.length;
|
|
34
|
+
}
|
|
35
|
+
get atomic_chunk_arr() {
|
|
36
|
+
return this.chunks[0].iterable;
|
|
37
|
+
}
|
|
38
|
+
chunks_update_thresholds_after(chunk_index, diff) {
|
|
39
|
+
const results = [];
|
|
40
|
+
for (let end1 = this.chunk_thresholds.length, i1 = chunk_index; i1 < end1; ++i1) {
|
|
41
|
+
const index = i1;
|
|
42
|
+
results.push(this.chunk_thresholds[index] += diff);
|
|
43
|
+
}
|
|
44
|
+
;
|
|
45
|
+
return results;
|
|
46
|
+
}
|
|
47
|
+
entry() {
|
|
48
|
+
var _a, _b;
|
|
49
|
+
if (!this.calculated) {
|
|
50
|
+
const max1 = Math.max(...this.iterable.map($2 => $2[1]));
|
|
51
|
+
this.max = max1;
|
|
52
|
+
const min1 = Math.min(...this.iterable.map($3 => $3[1]));
|
|
53
|
+
this.min = min1;
|
|
54
|
+
const chunk_range1 = Math.ceil((this.max - this.min) / (this.chunks_count - 1));
|
|
55
|
+
this.chunk_range = chunk_range1;
|
|
56
|
+
this.is_atomic = ((this.chunks_count >= this.length) || (this.max - this.min === 0));
|
|
57
|
+
const chunks1 = (() => {
|
|
58
|
+
if (!this.is_atomic) {
|
|
59
|
+
const chunks = [...new Array(this.chunks_count)].map(() => []);
|
|
60
|
+
this.iterable.forEach((x) => {
|
|
61
|
+
return chunks[Math.floor((x[1] - this.min) / this.chunk_range)].push(x);
|
|
62
|
+
});
|
|
63
|
+
return chunks.map($4 => new LazySort($4, { revert: this.revert, chunks_count: this.chunks_count, emulate: this.emulate }));
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
return [new LazySort(this.iterable.toSorted((a, b) => (-1) ** +this.revert * (a[1] - b[1])), { revert: this.revert, chunks_count: this.chunks_count, emulate: this.emulate })];
|
|
67
|
+
}
|
|
68
|
+
})();
|
|
69
|
+
this.chunks = chunks1;
|
|
70
|
+
this.revert && ((_a = this.chunks) === null || _a === void 0 ? void 0 : _a.reverse());
|
|
71
|
+
const chunk_thresholds1 = (_b = this.chunks) === null || _b === void 0 ? void 0 : _b.reduce((acc, next) => acc.concat([(acc[acc.length - 1] || 0) + next.length]), []);
|
|
72
|
+
this.chunk_thresholds = chunk_thresholds1;
|
|
73
|
+
}
|
|
74
|
+
this.calculated = true;
|
|
75
|
+
switch (this.emulate) {
|
|
76
|
+
case 0 /* ArrayEmulateStrategy.Partial */: {
|
|
77
|
+
return __classPrivateFieldGet(this, _LazySort_instances, "m", _LazySort_to_partial_array_emulator).call(this);
|
|
78
|
+
}
|
|
79
|
+
case 1 /* ArrayEmulateStrategy.Proxied */: {
|
|
80
|
+
return __classPrivateFieldGet(this, _LazySort_instances, "m", _LazySort_to_proxied_array_emulator).call(this);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
_LazySort_instances = new WeakSet(), _LazySort_to_proxied_array_emulator = function _LazySort_to_proxied_array_emulator() {
|
|
86
|
+
const instance = __classPrivateFieldGet(this, _LazySort_instances, "m", _LazySort_to_partial_array_emulator).call(this);
|
|
87
|
+
return instance;
|
|
88
|
+
}, _LazySort_to_partial_array_emulator = function _LazySort_to_partial_array_emulator() {
|
|
89
|
+
return new LazySortEntry(this);
|
|
90
|
+
};
|
|
91
|
+
export class LazySortEntry extends Array {
|
|
92
|
+
constructor(source) {
|
|
93
|
+
super();
|
|
94
|
+
_LazySortEntry_source.set(this, void 0);
|
|
95
|
+
__classPrivateFieldSet(this, _LazySortEntry_source, source, "f");
|
|
96
|
+
}
|
|
97
|
+
entry() {
|
|
98
|
+
return this;
|
|
99
|
+
}
|
|
100
|
+
get length() {
|
|
101
|
+
return __classPrivateFieldGet(this, _LazySortEntry_source, "f").length;
|
|
102
|
+
}
|
|
103
|
+
set length(value) {
|
|
104
|
+
let ref;
|
|
105
|
+
((ref = this.toArray()).length = value, ref);
|
|
106
|
+
}
|
|
107
|
+
*[(_LazySortEntry_source = new WeakMap(), Symbol.iterator)]() {
|
|
108
|
+
for (let end2 = __classPrivateFieldGet(this, _LazySortEntry_source, "f").length, i2 = 0; i2 < end2; ++i2) {
|
|
109
|
+
const index = i2;
|
|
110
|
+
yield this.positive_at(index);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
toArray() {
|
|
114
|
+
if (__classPrivateFieldGet(this, _LazySortEntry_source, "f").is_atomic) {
|
|
115
|
+
return __classPrivateFieldGet(this, _LazySortEntry_source, "f").atomic_chunk_arr;
|
|
116
|
+
}
|
|
117
|
+
return __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunks.map($5 => $5.entry().toArray()).flat();
|
|
118
|
+
}
|
|
119
|
+
positive_at(at) {
|
|
120
|
+
if (__classPrivateFieldGet(this, _LazySortEntry_source, "f").is_atomic) {
|
|
121
|
+
return __classPrivateFieldGet(this, _LazySortEntry_source, "f").atomic_chunk_arr[at];
|
|
122
|
+
}
|
|
123
|
+
const chunk_index = __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunk_thresholds.findIndex((a1 => a1 > at));
|
|
124
|
+
if (chunk_index === -1) {
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
const chunk = __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunks[chunk_index];
|
|
128
|
+
return chunk.entry().positive_at(at - (__classPrivateFieldGet(this, _LazySortEntry_source, "f").chunk_thresholds[chunk_index - 1] || 0));
|
|
129
|
+
}
|
|
130
|
+
find(predicate) {
|
|
131
|
+
return this.positive_at(this.findIndex(predicate));
|
|
132
|
+
}
|
|
133
|
+
findIndex(predicate) {
|
|
134
|
+
for (let end3 = this.length, i3 = 0; i3 < end3; ++i3) {
|
|
135
|
+
const index = i3;
|
|
136
|
+
if (predicate(this.positive_at(index), index, this)) {
|
|
137
|
+
return index;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return -1;
|
|
141
|
+
}
|
|
142
|
+
findLast(predicate) {
|
|
143
|
+
return this.positive_at(this.findIndexLast(predicate));
|
|
144
|
+
}
|
|
145
|
+
findIndexLast(predicate) {
|
|
146
|
+
for (let i4 = this.length + -1; i4 >= 0; --i4) {
|
|
147
|
+
const index = i4;
|
|
148
|
+
if (predicate(this.positive_at(index), index, this)) {
|
|
149
|
+
return index;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return -1;
|
|
153
|
+
}
|
|
154
|
+
indexOf(item) {
|
|
155
|
+
if (__classPrivateFieldGet(this, _LazySortEntry_source, "f").is_atomic) {
|
|
156
|
+
return __classPrivateFieldGet(this, _LazySortEntry_source, "f").atomic_chunk_arr.indexOf(item);
|
|
157
|
+
}
|
|
158
|
+
let results1;
|
|
159
|
+
results1 = [];
|
|
160
|
+
let ref1;
|
|
161
|
+
for (const chunk_index in ref1 = __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunks) {
|
|
162
|
+
const chunk = ref1[chunk_index];
|
|
163
|
+
let ref2;
|
|
164
|
+
if ((ref2 = chunk.entry().indexOf(item))) {
|
|
165
|
+
const index = ref2;
|
|
166
|
+
results1 = [index, +chunk_index];
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
results1.push(void 0);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
;
|
|
174
|
+
const [index, chunk_index] = results1;
|
|
175
|
+
if (chunk_index === undefined) {
|
|
176
|
+
return -1;
|
|
177
|
+
}
|
|
178
|
+
return (__classPrivateFieldGet(this, _LazySortEntry_source, "f").chunk_thresholds[chunk_index - 1] || 0) + index;
|
|
179
|
+
}
|
|
180
|
+
some(predicate) {
|
|
181
|
+
return (this.findIndex(predicate)) !== -1;
|
|
182
|
+
}
|
|
183
|
+
// @ts-expect-error
|
|
184
|
+
every(predicate) {
|
|
185
|
+
return !this.some(predicate);
|
|
186
|
+
}
|
|
187
|
+
splice(start, deleteCount, ...items) {
|
|
188
|
+
start < 0 && (start = __classPrivateFieldGet(this, _LazySortEntry_source, "f").length + start);
|
|
189
|
+
(start + deleteCount > __classPrivateFieldGet(this, _LazySortEntry_source, "f").length) && (deleteCount = __classPrivateFieldGet(this, _LazySortEntry_source, "f").length - start);
|
|
190
|
+
(deleteCount - items.length !== 0) && (__classPrivateFieldGet(this, _LazySortEntry_source, "f").length -= (deleteCount - items.length));
|
|
191
|
+
if (__classPrivateFieldGet(this, _LazySortEntry_source, "f").is_atomic) {
|
|
192
|
+
return __classPrivateFieldGet(this, _LazySortEntry_source, "f").atomic_chunk_arr.splice(start, deleteCount, ...items);
|
|
193
|
+
}
|
|
194
|
+
const end = start + deleteCount;
|
|
195
|
+
const removed = [];
|
|
196
|
+
const ret = removed;
|
|
197
|
+
__classPrivateFieldGet(this, _LazySortEntry_source, "f").chunks
|
|
198
|
+
.map((chunk, chunk_index) => {
|
|
199
|
+
return ({
|
|
200
|
+
chunk_start: __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunk_thresholds[chunk_index - 1] || 0,
|
|
201
|
+
chunk_end: __classPrivateFieldGet(this, _LazySortEntry_source, "f").chunk_thresholds[chunk_index],
|
|
202
|
+
chunk,
|
|
203
|
+
chunk_index
|
|
204
|
+
});
|
|
205
|
+
})
|
|
206
|
+
.filter(({ chunk_start, chunk_end, chunk }) => {
|
|
207
|
+
if (!chunk.length) {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
return start < chunk_end && chunk_start <= end;
|
|
211
|
+
})
|
|
212
|
+
.forEach(({ chunk_start, chunk_end, chunk_index, chunk }, changed_index, changes_array) => {
|
|
213
|
+
const replace_start = changed_index === 0
|
|
214
|
+
? start - chunk_start
|
|
215
|
+
: 0;
|
|
216
|
+
const replace_end = changed_index === changes_array.length - 1
|
|
217
|
+
? end - chunk_start
|
|
218
|
+
: chunk.length;
|
|
219
|
+
const _removed_count = replace_end - replace_start;
|
|
220
|
+
const _added_items = items.slice(replace_start + chunk_start - start, changed_index === changes_array.length - 1 ? undefined : replace_end + chunk_start - start);
|
|
221
|
+
__classPrivateFieldGet(this, _LazySortEntry_source, "f").chunks_update_thresholds_after(chunk_index, _added_items.length - _removed_count);
|
|
222
|
+
return concatAssign(removed, chunk.entry().splice(replace_start, _removed_count, ..._added_items));
|
|
223
|
+
});
|
|
224
|
+
return ret;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// slice()
|
|
228
|
+
// push()
|
|
229
|
+
// pop()
|
|
230
|
+
// unshift()
|
|
231
|
+
// shift()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { LazySort } from "./LazySort.build.js";
|
|
2
|
+
import { describe, expect, test } from "vitest";
|
|
3
|
+
describe("LazySortEntry.splice", () => {
|
|
4
|
+
test("Splice removes and inserts elements correctly", () => {
|
|
5
|
+
const source = LazySort.ofNumbers([
|
|
6
|
+
5, 1, 3, 4, 2, 17, 11, 10, 9, 15, 14, 16, 13, 12, 7, 8, 6, 199,
|
|
7
|
+
]);
|
|
8
|
+
const entry = source.entry();
|
|
9
|
+
// Проверка начального состояния
|
|
10
|
+
expect(source.length).toBe(18);
|
|
11
|
+
expect(entry.toArray().map(([value]) => value)).toEqual([
|
|
12
|
+
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 199,
|
|
13
|
+
]);
|
|
14
|
+
// Удаление элементов
|
|
15
|
+
const removed = entry.splice(5, 3); // Удаляем элементы с 6-й по 8-й (0-индексация)
|
|
16
|
+
expect(removed.map(([value]) => value)).toEqual([6, 7, 8]);
|
|
17
|
+
// Проверяем обновленное состояние
|
|
18
|
+
expect(source.length).toBe(15);
|
|
19
|
+
expect(entry.toArray().map(([value]) => value)).toEqual([
|
|
20
|
+
1, 2, 3, 4, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17, 199,
|
|
21
|
+
]);
|
|
22
|
+
// Вставка элементов
|
|
23
|
+
entry.splice(2, 0, [99, 99], [98, 98]); // Вставляем два элемента после второго
|
|
24
|
+
expect(source.length).toBe(17);
|
|
25
|
+
expect(entry.toArray().map(([value]) => value)).toEqual([
|
|
26
|
+
1, 2, 99, 98, 3, 4, 5, 9, 10, 11, 12, 13, 14, 15, 16, 17, 199,
|
|
27
|
+
]);
|
|
28
|
+
// Удаление и замена
|
|
29
|
+
// 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
|
|
30
|
+
const replaced = entry.splice(9, 2, [77, 77]);
|
|
31
|
+
expect(replaced.map(([value]) => value)).toEqual([11, 12]);
|
|
32
|
+
expect(source.length).toBe(16);
|
|
33
|
+
expect(entry.toArray().map(([value]) => value)).toEqual([
|
|
34
|
+
1, 2, 99, 98, 3, 4, 5, 9, 10, 77, 13, 14, 15, 16, 17, 199,
|
|
35
|
+
]);
|
|
36
|
+
});
|
|
37
|
+
test("Chunk with 199 remains unchanged", () => {
|
|
38
|
+
const source = LazySort.ofNumbers([
|
|
39
|
+
5, 1, 3, 4, 2, 17, 11, 10, 9, 15, 14, 16, 13, 12, 7, 8, 6, 199,
|
|
40
|
+
]);
|
|
41
|
+
const entry = source.entry();
|
|
42
|
+
// Проверяем, что чанк с элементом 199 еще не был просчитан
|
|
43
|
+
const chunkWith199Index = source.chunks.findIndex((chunk) => chunk.iterable.some(([value]) => value === 199));
|
|
44
|
+
expect(chunkWith199Index).not.toBe(-1); // Чанк должен существовать
|
|
45
|
+
const chunkWith199 = source.chunks[chunkWith199Index];
|
|
46
|
+
// Убеждаемся, что чанк не просчитан
|
|
47
|
+
expect(chunkWith199.calculated).toBe(false);
|
|
48
|
+
// Выполняем операцию, которая не должна затрагивать чанк с 199
|
|
49
|
+
entry.splice(5, 3);
|
|
50
|
+
// Убедимся, что чанк с 199 остался непросчитанным
|
|
51
|
+
expect(chunkWith199.calculated).toBe(false);
|
|
52
|
+
// Проверяем, что сам чанк не изменился
|
|
53
|
+
expect(chunkWith199.iterable.some(([value]) => value === 199)).toBe(true);
|
|
54
|
+
entry.splice(-1, 0, [200, 200]);
|
|
55
|
+
expect(chunkWith199.calculated).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
test("Reverse", () => {
|
|
58
|
+
const iterable = [
|
|
59
|
+
5, 1, 3, 4, 2, 17, 11, 10, 9, 15, 14, 16, 13, 12, 7, 8, 6, 199,
|
|
60
|
+
].map(($) => [$, $]);
|
|
61
|
+
const source = new LazySort(iterable, {
|
|
62
|
+
revert: true,
|
|
63
|
+
});
|
|
64
|
+
const result = source.entry().toArray();
|
|
65
|
+
expect(result.map(([value]) => value)).toEqual([
|
|
66
|
+
199, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
|
|
67
|
+
]);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -5,7 +5,9 @@ interface IParams<T> {
|
|
|
5
5
|
filter?: (item: T) => boolean;
|
|
6
6
|
}
|
|
7
7
|
interface IPickContext<T> {
|
|
8
|
-
busy_preventable: ReturnType<typeof create_default_preventable
|
|
8
|
+
busy_preventable: ReturnType<typeof create_default_preventable> & {
|
|
9
|
+
require_insert(): void;
|
|
10
|
+
};
|
|
9
11
|
item: T;
|
|
10
12
|
pick: (context: IPickContext<T>) => boolean;
|
|
11
13
|
threshold: number;
|
|
@@ -22,6 +24,8 @@ export declare class RandomizerContext<T> {
|
|
|
22
24
|
}): RandomizerContext<T>;
|
|
23
25
|
pickRandom(pick?: IPickContext<T>["pick"]): T | undefined;
|
|
24
26
|
}
|
|
27
|
+
export declare function pickInThresholds(thresholds: number[], value: number): number;
|
|
28
|
+
export declare function thresholdsOf(weights: NonNullable<IParams<unknown>["associatedWeights"]>): number[];
|
|
25
29
|
export declare function getRandomElementIndexInWeights(weights: NonNullable<IParams<unknown>["associatedWeights"]>): number | never;
|
|
26
|
-
export declare function getRandomElementFromArray<T>(array: T[], { associatedWeights, filter }?: IParams<T>):
|
|
30
|
+
export declare function getRandomElementFromArray<T>(array: T[], { associatedWeights, filter }?: IParams<T>): T | undefined;
|
|
27
31
|
export {};
|
|
@@ -1,57 +1,74 @@
|
|
|
1
|
+
import assert from "node:assert";
|
|
1
2
|
import { binary_search } from "../primitives/binary_search.js";
|
|
2
3
|
import { create_default_preventable } from "../primitives/createDefaultPreventable.js";
|
|
3
|
-
import { BusyNumeric } from "./BusyNumeric.js";
|
|
4
|
+
import { BusyNumeric, size_of_area } from "./BusyNumeric.js";
|
|
4
5
|
import { getRandomNumberInRange } from "./getRandomNumberInRange.js";
|
|
5
6
|
export class RandomizerContext {
|
|
6
7
|
constructor(array, thresholds) {
|
|
7
8
|
var _a;
|
|
8
9
|
this.array = array;
|
|
9
10
|
this.thresholds = thresholds;
|
|
10
|
-
const range = (_a = thresholds === null || thresholds === void 0 ? void 0 : thresholds.at(-1)) !== null && _a !== void 0 ? _a : array.length;
|
|
11
|
+
const range = (_a = thresholds === null || thresholds === void 0 ? void 0 : thresholds.at(-1)) !== null && _a !== void 0 ? _a : array.length - 1;
|
|
11
12
|
this.hotel = new BusyNumeric(range);
|
|
12
13
|
}
|
|
13
14
|
static from({ array, associatedWeights, }) {
|
|
14
|
-
const thresholds = associatedWeights &&
|
|
15
|
-
_getRandomElementIndexInWeight_thresholds(associatedWeights);
|
|
15
|
+
const thresholds = associatedWeights && thresholdsOf(associatedWeights);
|
|
16
16
|
return new RandomizerContext(array, thresholds);
|
|
17
17
|
}
|
|
18
18
|
pickRandom(pick = () => true) {
|
|
19
|
-
var _a;
|
|
20
19
|
const { hotel, thresholds, array } = this;
|
|
21
20
|
while (true) {
|
|
22
21
|
const segments_count = hotel.segments_count();
|
|
23
22
|
if (!segments_count) {
|
|
24
23
|
break;
|
|
25
24
|
}
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
const target_of_free = getRandomNumberInRange({ max: hotel.free_area - 1 });
|
|
26
|
+
const position = (() => {
|
|
27
|
+
var _a, _b, _c, _d;
|
|
28
|
+
let segment = 0;
|
|
29
|
+
let distance = target_of_free;
|
|
30
|
+
let position = 0;
|
|
31
|
+
while (true) {
|
|
32
|
+
const free_area = ((_b = (_a = hotel.busy_areas[segment]) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : hotel.range + 1) - ((_d = (_c = hotel.busy_areas[segment - 1]) === null || _c === void 0 ? void 0 : _c[1]) !== null && _d !== void 0 ? _d : -1) - 1;
|
|
33
|
+
distance -= free_area;
|
|
34
|
+
position += free_area;
|
|
35
|
+
if (distance < 0) {
|
|
36
|
+
return position + distance;
|
|
37
|
+
}
|
|
38
|
+
position += size_of_area(hotel.busy_areas[segment] || [0, hotel.range + 1]);
|
|
39
|
+
segment++;
|
|
40
|
+
}
|
|
41
|
+
})();
|
|
42
|
+
let _require_insert = false;
|
|
43
|
+
const index = thresholds ? pickInThresholds(thresholds, position) : position;
|
|
31
44
|
const element = array[index];
|
|
32
45
|
const pickContext = {
|
|
33
|
-
busy_preventable:
|
|
46
|
+
busy_preventable: {
|
|
47
|
+
...create_default_preventable(),
|
|
48
|
+
require_insert() {
|
|
49
|
+
_require_insert = true;
|
|
50
|
+
}
|
|
51
|
+
},
|
|
34
52
|
item: element,
|
|
35
53
|
pick,
|
|
36
54
|
threshold: index,
|
|
37
|
-
point,
|
|
55
|
+
point: position,
|
|
38
56
|
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
if (!pickContext.busy_preventable.default_prevented()) {
|
|
57
|
+
const picked = pick(pickContext);
|
|
58
|
+
if (_require_insert || !picked && !pickContext.busy_preventable.default_prevented()) {
|
|
43
59
|
thresholds
|
|
44
60
|
? hotel.insert_area(thresholds[index - 1] + 1 || 0, thresholds[index])
|
|
45
61
|
: hotel.bifurcate(index);
|
|
46
62
|
}
|
|
63
|
+
if (picked) {
|
|
64
|
+
return element;
|
|
65
|
+
}
|
|
47
66
|
}
|
|
48
67
|
return undefined;
|
|
49
68
|
}
|
|
50
69
|
}
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
return -1;
|
|
54
|
-
}
|
|
70
|
+
export function pickInThresholds(thresholds, value) {
|
|
71
|
+
assert(thresholds.length > 0);
|
|
55
72
|
return binary_search(thresholds.length - 1, (index) => {
|
|
56
73
|
var _a;
|
|
57
74
|
const hold = thresholds[index];
|
|
@@ -64,17 +81,15 @@ function _getRandomElementIndexInWeight_of_thresholds(thresholds, value) {
|
|
|
64
81
|
return 1;
|
|
65
82
|
});
|
|
66
83
|
}
|
|
67
|
-
function
|
|
68
|
-
|
|
69
|
-
new Error("Invalid array length");
|
|
70
|
-
}
|
|
84
|
+
export function thresholdsOf(weights) {
|
|
85
|
+
assert(weights.length > 0, "Invalid array length");
|
|
71
86
|
let previousLimit = 0;
|
|
72
87
|
return weights.map((weight) => (previousLimit += weight));
|
|
73
88
|
}
|
|
74
89
|
export function getRandomElementIndexInWeights(weights) {
|
|
75
|
-
const thresholds =
|
|
76
|
-
const
|
|
77
|
-
return
|
|
90
|
+
const thresholds = thresholdsOf(weights);
|
|
91
|
+
const lotteryPick = Math.random() * thresholds.at(-1);
|
|
92
|
+
return pickInThresholds(thresholds, lotteryPick);
|
|
78
93
|
}
|
|
79
94
|
// task: честный алгоритм , для которого каждый из элеметов списка имеет равный шанс на реализацию своей вероятности.
|
|
80
95
|
// Обычно весь список фильтруется и после выбирается элемент. В нашем случае фильтр будет срабатывать только для тех элементов,
|
|
@@ -93,10 +108,8 @@ export function getRandomElementIndexInWeights(weights) {
|
|
|
93
108
|
Повторяем
|
|
94
109
|
*/
|
|
95
110
|
export function getRandomElementFromArray(array, { associatedWeights, filter = () => true } = {}) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
RandomizerContext.from({
|
|
111
|
+
assert(!associatedWeights || associatedWeights.length === array.length, "Incorrectly passed argument associatedWeights: The length of the associatedWeights must exactly match the length of the weights array");
|
|
112
|
+
return RandomizerContext.from({
|
|
100
113
|
array,
|
|
101
114
|
associatedWeights,
|
|
102
115
|
}).pickRandom(({ item }) => filter(item));
|
|
@@ -86,7 +86,7 @@ export declare class CliParser {
|
|
|
86
86
|
}): this;
|
|
87
87
|
replaceByMatch(regex: RegExp): RegExpMatchArray | null;
|
|
88
88
|
captureByMatch({ regex, name }: ITextMatch): this;
|
|
89
|
-
|
|
89
|
+
replaceSlice(start: number, length: number, replacer: (string: string) => string): void;
|
|
90
90
|
collect(): CliParserRunContext;
|
|
91
91
|
static CliParserRunContext: typeof CliParserRunContext;
|
|
92
92
|
static CapturedContent: typeof CapturedContent;
|
|
@@ -46,7 +46,7 @@ export class FlagsManager {
|
|
|
46
46
|
captureResidueFlags(context) {
|
|
47
47
|
let match;
|
|
48
48
|
const { parser } = context;
|
|
49
|
-
while ((match = parser.replaceByMatch(
|
|
49
|
+
while ((match = parser.replaceByMatch(/(?<flag>-{1,2}\w+)(?:(?<separator>\s+(?!-)|=)(?<value>\S+))?/))) {
|
|
50
50
|
this.unhandledFlags || (this.unhandledFlags = []);
|
|
51
51
|
this.unhandledFlags.push(match);
|
|
52
52
|
}
|
|
@@ -55,7 +55,7 @@ export class FlagsManager {
|
|
|
55
55
|
captureFlags(flags, context) {
|
|
56
56
|
for (const { name, capture, expectValue } of flags) {
|
|
57
57
|
for (const flag of capture) {
|
|
58
|
-
const regex = `(?<=^|\\s)
|
|
58
|
+
const regex = `(?<=^|\\s)(?<flag>${flag})${expectValue ? "(?:(?<separator>\\s+(?!-)|=)(?<value>[^\\s]+))?" : ""}`;
|
|
59
59
|
const { parser } = context;
|
|
60
60
|
const captureName = name || flag;
|
|
61
61
|
const match = parser.replaceByMatch(RegExp(regex, "i"));
|
|
@@ -109,8 +109,8 @@ export class CapturedContent {
|
|
|
109
109
|
}
|
|
110
110
|
static contentIsRegExpMatchArray(content) {
|
|
111
111
|
return (content instanceof Array &&
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
content.hasOwnProperty("index") &&
|
|
113
|
+
content.hasOwnProperty("input"));
|
|
114
114
|
}
|
|
115
115
|
static contentIsString(content) {
|
|
116
116
|
return typeof content === "string";
|
|
@@ -196,7 +196,7 @@ export class CliParser {
|
|
|
196
196
|
const group = groups[index];
|
|
197
197
|
const replacement = context.brackets.toStringGroup(indexes[index]);
|
|
198
198
|
const length = group.length;
|
|
199
|
-
this.
|
|
199
|
+
this.replaceSlice(group.indexInText - offset, length, () => replacement);
|
|
200
200
|
offset += length - replacement.length;
|
|
201
201
|
}
|
|
202
202
|
return this;
|
|
@@ -218,9 +218,14 @@ export class CliParser {
|
|
|
218
218
|
}
|
|
219
219
|
captureResidue({ name }) {
|
|
220
220
|
const { context } = this;
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
221
|
+
const raw = context.input;
|
|
222
|
+
const value = (() => {
|
|
223
|
+
const stop_hyphen = /^\s+-\s+/;
|
|
224
|
+
const clean = raw.replace(stop_hyphen, "").trim();
|
|
225
|
+
return clean;
|
|
226
|
+
})();
|
|
227
|
+
this.replaceSlice(0, raw.length, () => "");
|
|
228
|
+
context.captures.set(name, new CapturedContent(value).setContextInstance(context));
|
|
224
229
|
return this;
|
|
225
230
|
}
|
|
226
231
|
replaceByMatch(regex) {
|
|
@@ -233,7 +238,7 @@ export class CliParser {
|
|
|
233
238
|
if (indexInText === undefined) {
|
|
234
239
|
throw new Error("Match without index");
|
|
235
240
|
}
|
|
236
|
-
this.
|
|
241
|
+
this.replaceSlice(indexInText, full.length, () => "");
|
|
237
242
|
return matched;
|
|
238
243
|
}
|
|
239
244
|
captureByMatch({ regex, name }) {
|
|
@@ -242,7 +247,7 @@ export class CliParser {
|
|
|
242
247
|
context.captures.set(name, matched ? new CapturedContent(matched).setContextInstance(context) : null);
|
|
243
248
|
return this;
|
|
244
249
|
}
|
|
245
|
-
|
|
250
|
+
replaceSlice(start, length, replacer) {
|
|
246
251
|
const { context } = this;
|
|
247
252
|
const before = context.input.slice(0, start);
|
|
248
253
|
const after = context.input.slice(start + length);
|
|
@@ -1 +1,9 @@
|
|
|
1
1
|
export declare function binary_search(max: number, compare: (index: number) => number): number;
|
|
2
|
+
export declare const enum BinarySearchResultEnum {
|
|
3
|
+
NotFound = -1
|
|
4
|
+
}
|
|
5
|
+
export declare const enum BinarySearchCompareSpec {
|
|
6
|
+
Biggest = 1,
|
|
7
|
+
Equal = 0,
|
|
8
|
+
Smallest = -1
|
|
9
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function
|
|
1
|
+
export declare function normalize_to_max_coefficient(list: number[]): number[];
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export function
|
|
2
|
-
// (
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export function normalize_to_max_coefficient(list) {
|
|
2
|
+
// normalize_to_optimal(2, MAX_SAFE_INTEGER) will be coefficient 1:9007199254740990
|
|
3
|
+
// normalize_to_optimal(0.25, 3000) will be coefficient 750537393112:9006448717347879
|
|
4
|
+
const sum = list.reduce((acc, value) => acc + value, 0);
|
|
5
|
+
const multiplayer = Number.MAX_SAFE_INTEGER / sum;
|
|
6
|
+
return list.map((x) => Math.floor(x * multiplayer));
|
|
5
7
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zoodogood/utils",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.2.0-change.3344",
|
|
5
5
|
"description": "",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"homepage": "https://zoodogood.github.io/utils",
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
"scripts": {
|
|
69
|
-
"test": "vitest --
|
|
69
|
+
"test": "vitest --run",
|
|
70
70
|
"docs-build": "cd ./docs && retype build --output ./public",
|
|
71
71
|
"docs-watch": "cd ./docs && retype watch",
|
|
72
72
|
"build": "tsc",
|