sorted-collections 1.0.2
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/LICENSE +21 -0
- package/README.md +258 -0
- package/dist/index.cjs +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +431 -0
- package/dist/index.d.ts +431 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +82 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A standard JS/TS comparator: negative if `a` sorts before `b`, positive if
|
|
3
|
+
* after, zero if equal.
|
|
4
|
+
*/
|
|
5
|
+
type Comparator<T> = (a: T, b: T) => number;
|
|
6
|
+
interface SortedOptions<T> {
|
|
7
|
+
comparator?: Comparator<T>;
|
|
8
|
+
}
|
|
9
|
+
interface SortedOptionsRequired<T> {
|
|
10
|
+
comparator: Comparator<T>;
|
|
11
|
+
}
|
|
12
|
+
/** Types with a natural order (`<`/`>`) usable without an explicit comparator. */
|
|
13
|
+
type NaturallyOrderable = number | string;
|
|
14
|
+
/**
|
|
15
|
+
* Rest-tuple used in constructors so TypeScript enforces a comparator at
|
|
16
|
+
* compile time for any `T` that isn't naturally orderable, while keeping it
|
|
17
|
+
* optional for `number`/`string`.
|
|
18
|
+
*/
|
|
19
|
+
type ComparatorArg<T> = T extends NaturallyOrderable ? [options?: SortedOptions<T>] : [options: SortedOptionsRequired<T>];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A list that keeps its elements in sorted order as they're inserted.
|
|
23
|
+
*
|
|
24
|
+
* A thin public wrapper around the internal {@link BucketEngine} — see there
|
|
25
|
+
* for the actual "list of lists" (sqrt-decomposition) implementation and its
|
|
26
|
+
* complexity notes.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* const scores = new SortedList<number>([42, 7, 99]);
|
|
31
|
+
* scores.add(15);
|
|
32
|
+
* [...scores]; // [7, 15, 42, 99]
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
declare class SortedList<T> implements Iterable<T> {
|
|
36
|
+
private readonly engine;
|
|
37
|
+
/**
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* new SortedList<number>(); // empty
|
|
41
|
+
* new SortedList<number>([3, 1, 2]); // [1, 2, 3]
|
|
42
|
+
* new SortedList<Person>([...], { comparator: (a, b) => a.age - b.age });
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
constructor(iterable?: Iterable<T>, ...options: ComparatorArg<T>);
|
|
46
|
+
/** Safe to call from subclasses/clone: both `ComparatorArg<T>` branches accept `{ comparator }`. */
|
|
47
|
+
protected comparatorArg(): ComparatorArg<T>;
|
|
48
|
+
/**
|
|
49
|
+
* O(√n) amortized.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* const scores = new SortedList<number>();
|
|
54
|
+
* scores.add(42);
|
|
55
|
+
* scores.add(7);
|
|
56
|
+
* [...scores]; // [7, 42]
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
add(value: T): void;
|
|
60
|
+
/**
|
|
61
|
+
* Bulk-inserts every value from `iterable`, one {@link add} at a time.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* const scores = new SortedList<number>([3, 1]);
|
|
66
|
+
* scores.update([2, 5, 4]);
|
|
67
|
+
* [...scores]; // [1, 2, 3, 4, 5]
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
update(iterable: Iterable<T>): void;
|
|
71
|
+
/**
|
|
72
|
+
* Removes the first occurrence of `value`. Returns `false` if it wasn't present.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```ts
|
|
76
|
+
* const scores = new SortedList<number>([1, 2, 2, 3]);
|
|
77
|
+
* scores.remove(2); // true — removes one occurrence
|
|
78
|
+
* scores.remove(99); // false — not present
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
remove(value: T): boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Like {@link remove}, but never throws (or returns anything) if `value` isn't present.
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* const scores = new SortedList<number>([1, 2, 3]);
|
|
88
|
+
* scores.discard(99); // no-op, no error
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
discard(value: T): void;
|
|
92
|
+
/**
|
|
93
|
+
* Removes and returns the element at `index` (default: the last element).
|
|
94
|
+
* Negative indices count from the end, same as {@link at}.
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```ts
|
|
98
|
+
* const scores = new SortedList<number>([10, 20, 30]);
|
|
99
|
+
* scores.pop(); // 30 — last element
|
|
100
|
+
* scores.pop(0); // 10 — first element
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
pop(index?: number): T;
|
|
104
|
+
/**
|
|
105
|
+
* O(√n): walks bucket lengths to find the element at `index` (negative indices count from the end).
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```ts
|
|
109
|
+
* const scores = new SortedList<number>([10, 20, 30]);
|
|
110
|
+
* scores.at(0); // 10
|
|
111
|
+
* scores.at(-1); // 30 — same as Array.prototype.at
|
|
112
|
+
* scores.at(99); // undefined — out of range
|
|
113
|
+
* ```
|
|
114
|
+
*/
|
|
115
|
+
at(index: number): T | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* The index of the first occurrence of `value`, or `-1` if absent.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```ts
|
|
121
|
+
* new SortedList<number>([1, 2, 2, 3]).indexOf(2); // 1
|
|
122
|
+
* new SortedList<number>([1, 2, 3]).indexOf(99); // -1
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
indexOf(value: T): number;
|
|
126
|
+
/**
|
|
127
|
+
* O(log n): binary search for the bucket, then binary search within it.
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* ```ts
|
|
131
|
+
* const scores = new SortedList<number>([1, 2, 3]);
|
|
132
|
+
* scores.has(2); // true
|
|
133
|
+
* scores.has(99); // false
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
has(value: T): boolean;
|
|
137
|
+
/**
|
|
138
|
+
* The leftmost index where `value` could be inserted while keeping the list sorted.
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* ```ts
|
|
142
|
+
* new SortedList<number>([1, 2, 2, 2, 3]).bisectLeft(2); // 1
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
bisectLeft(value: T): number;
|
|
146
|
+
/**
|
|
147
|
+
* The rightmost index where `value` could be inserted while keeping the list sorted.
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* ```ts
|
|
151
|
+
* new SortedList<number>([1, 2, 2, 2, 3]).bisectRight(2); // 4
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
bisectRight(value: T): number;
|
|
155
|
+
/**
|
|
156
|
+
* O(log n) to locate both bounds by value + O(k) to iterate the k results.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```ts
|
|
160
|
+
* const scores = new SortedList<number>([1, 2, 3, 4, 5]);
|
|
161
|
+
* [...scores.irange(2, 4)]; // [2, 3, 4] — inclusive by default
|
|
162
|
+
* [...scores.irange(2, 4, { inclusive: [false, true] })]; // [3, 4]
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
irange(min?: T, max?: T, options?: {
|
|
166
|
+
inclusive?: [boolean, boolean];
|
|
167
|
+
}): IterableIterator<T>;
|
|
168
|
+
/**
|
|
169
|
+
* O(√n) to locate both positional bounds + O(k) to iterate the k results.
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```ts
|
|
173
|
+
* const scores = new SortedList<number>([10, 20, 30, 40, 50]);
|
|
174
|
+
* [...scores.islice(1, 4)]; // [20, 30, 40] — like Array.prototype.slice
|
|
175
|
+
* ```
|
|
176
|
+
*/
|
|
177
|
+
islice(start?: number, end?: number): IterableIterator<T>;
|
|
178
|
+
/**
|
|
179
|
+
* @example
|
|
180
|
+
* ```ts
|
|
181
|
+
* new SortedList<number>([1, 2, 3]).length; // 3
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
get length(): number;
|
|
185
|
+
/**
|
|
186
|
+
* @example
|
|
187
|
+
* ```ts
|
|
188
|
+
* const scores = new SortedList<number>([1, 2, 3]);
|
|
189
|
+
* scores.clear();
|
|
190
|
+
* scores.length; // 0
|
|
191
|
+
* ```
|
|
192
|
+
*/
|
|
193
|
+
clear(): void;
|
|
194
|
+
/**
|
|
195
|
+
* An independent copy — mutating the clone never affects the original.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```ts
|
|
199
|
+
* const original = new SortedList<number>([1, 2, 3]);
|
|
200
|
+
* const copy = original.clone();
|
|
201
|
+
* copy.add(4);
|
|
202
|
+
* original.length; // 3
|
|
203
|
+
* copy.length; // 4
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
clone(): SortedList<T>;
|
|
207
|
+
/**
|
|
208
|
+
* @example
|
|
209
|
+
* ```ts
|
|
210
|
+
* const scores = new SortedList<number>([3, 1, 2]);
|
|
211
|
+
* for (const value of scores) console.log(value); // 1, 2, 3
|
|
212
|
+
* ```
|
|
213
|
+
*/
|
|
214
|
+
[Symbol.iterator](): IterableIterator<T>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Like {@link SortedList}, but rejects duplicates (compared via the
|
|
219
|
+
* comparator, not reference identity). Adds set-theory operations.
|
|
220
|
+
*
|
|
221
|
+
* Reuses `SortedList`'s bucket structure entirely: the only behavioral
|
|
222
|
+
* difference is that `add` is a no-op for values already present.
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```ts
|
|
226
|
+
* const tags = new SortedSet<string>(['b', 'a', 'c', 'a']);
|
|
227
|
+
* [...tags]; // ['a', 'b', 'c'] — the duplicate 'a' was dropped
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
declare class SortedSet<T> extends SortedList<T> {
|
|
231
|
+
/**
|
|
232
|
+
* O(log n) `has` check + O(√n) amortized insert if the value is new.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* ```ts
|
|
236
|
+
* const tags = new SortedSet<string>(['a']);
|
|
237
|
+
* tags.add('a'); // no-op, already present
|
|
238
|
+
* tags.length; // 1
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
add(value: T): void;
|
|
242
|
+
/**
|
|
243
|
+
* @example
|
|
244
|
+
* ```ts
|
|
245
|
+
* const original = new SortedSet<number>([1, 2, 3]);
|
|
246
|
+
* const copy = original.clone();
|
|
247
|
+
* copy.add(4);
|
|
248
|
+
* original.length; // 3
|
|
249
|
+
* ```
|
|
250
|
+
*/
|
|
251
|
+
clone(): SortedSet<T>;
|
|
252
|
+
/**
|
|
253
|
+
* O(m log n + m) for a set of size m being merged in.
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* ```ts
|
|
257
|
+
* const a = new SortedSet<number>([1, 2, 3]);
|
|
258
|
+
* const b = new SortedSet<number>([3, 4]);
|
|
259
|
+
* [...a.union(b)]; // [1, 2, 3, 4]
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
union(other: SortedSet<T>): SortedSet<T>;
|
|
263
|
+
/**
|
|
264
|
+
* @example
|
|
265
|
+
* ```ts
|
|
266
|
+
* const a = new SortedSet<number>([1, 2, 3]);
|
|
267
|
+
* const b = new SortedSet<number>([2, 3, 4]);
|
|
268
|
+
* [...a.intersection(b)]; // [2, 3]
|
|
269
|
+
* ```
|
|
270
|
+
*/
|
|
271
|
+
intersection(other: SortedSet<T>): SortedSet<T>;
|
|
272
|
+
/**
|
|
273
|
+
* @example
|
|
274
|
+
* ```ts
|
|
275
|
+
* const a = new SortedSet<number>([1, 2, 3]);
|
|
276
|
+
* const b = new SortedSet<number>([2, 3]);
|
|
277
|
+
* [...a.difference(b)]; // [1] — in a, not in b
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
difference(other: SortedSet<T>): SortedSet<T>;
|
|
281
|
+
/**
|
|
282
|
+
* @example
|
|
283
|
+
* ```ts
|
|
284
|
+
* new SortedSet<number>([2, 3]).isSubsetOf(new SortedSet<number>([1, 2, 3, 4])); // true
|
|
285
|
+
* new SortedSet<number>([1, 5]).isSubsetOf(new SortedSet<number>([1, 2, 3])); // false
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
isSubsetOf(other: SortedSet<T>): boolean;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* A dictionary ordered by key.
|
|
293
|
+
*
|
|
294
|
+
* Uses the internal {@link BucketEngine} directly (on `[K, V]` tuples, with a
|
|
295
|
+
* comparator that only looks at the key) rather than composing over
|
|
296
|
+
* `SortedList`'s public API. Two reasons: `set` needs the engine's O(log n)
|
|
297
|
+
* in-place replace-or-insert (`SortedList#bisectLeft` + `#at` would pay for a
|
|
298
|
+
* positional index it doesn't need), and `get`/`has`/`delete` use the `*By`
|
|
299
|
+
* lookup methods with a closure over the bare key — that compares the key
|
|
300
|
+
* only once per candidate (not twice, since the search side needs no
|
|
301
|
+
* `entry[0]` unwrapping) and avoids allocating a throwaway `[key, undefined]`
|
|
302
|
+
* search tuple per call.
|
|
303
|
+
*
|
|
304
|
+
* @example
|
|
305
|
+
* ```ts
|
|
306
|
+
* const byPrice = new SortedMap<number, string>([[101.5, 'order-1'], [99.75, 'order-2']]);
|
|
307
|
+
* [...byPrice.keys()]; // [99.75, 101.5]
|
|
308
|
+
* ```
|
|
309
|
+
*/
|
|
310
|
+
declare class SortedMap<K, V> implements Iterable<[K, V]> {
|
|
311
|
+
private readonly engine;
|
|
312
|
+
private readonly keyComparator;
|
|
313
|
+
/**
|
|
314
|
+
* @example
|
|
315
|
+
* ```ts
|
|
316
|
+
* new SortedMap<number, string>(); // empty
|
|
317
|
+
* new SortedMap<number, string>([[2, 'b'], [1, 'a']]); // ordered by key: 1, 2
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
constructor(entries?: Iterable<[K, V]>, ...options: ComparatorArg<K>);
|
|
321
|
+
/**
|
|
322
|
+
* O(log n) to locate + O(1) to replace in place, or O(√n) amortized to insert.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```ts
|
|
326
|
+
* const byPrice = new SortedMap<number, string>();
|
|
327
|
+
* byPrice.set(101.5, 'order-1');
|
|
328
|
+
* byPrice.set(101.5, 'order-1-updated'); // overwrites, doesn't grow size
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
set(key: K, value: V): void;
|
|
332
|
+
/**
|
|
333
|
+
* O(log n): binary search for the bucket, then binary search within it.
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```ts
|
|
337
|
+
* const byPrice = new SortedMap<number, string>([[101.5, 'order-1']]);
|
|
338
|
+
* byPrice.get(101.5); // 'order-1'
|
|
339
|
+
* byPrice.get(1); // undefined
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
get(key: K): V | undefined;
|
|
343
|
+
/**
|
|
344
|
+
* @example
|
|
345
|
+
* ```ts
|
|
346
|
+
* const byPrice = new SortedMap<number, string>([[101.5, 'order-1']]);
|
|
347
|
+
* byPrice.delete(101.5); // true
|
|
348
|
+
* byPrice.delete(101.5); // false — already gone
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
351
|
+
delete(key: K): boolean;
|
|
352
|
+
/**
|
|
353
|
+
* @example
|
|
354
|
+
* ```ts
|
|
355
|
+
* new SortedMap<number, string>([[1, 'a']]).has(1); // true
|
|
356
|
+
* ```
|
|
357
|
+
*/
|
|
358
|
+
has(key: K): boolean;
|
|
359
|
+
/**
|
|
360
|
+
* A snapshot `SortedSet` of the current keys — not a live view.
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```ts
|
|
364
|
+
* const byPrice = new SortedMap<number, string>([[2, 'b'], [1, 'a']]);
|
|
365
|
+
* [...byPrice.keys()]; // [1, 2]
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
keys(): SortedSet<K>;
|
|
369
|
+
private keysGenerator;
|
|
370
|
+
/**
|
|
371
|
+
* @example
|
|
372
|
+
* ```ts
|
|
373
|
+
* [...new SortedMap<number, string>([[2, 'b'], [1, 'a']]).values()]; // ['a', 'b']
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
values(): IterableIterator<V>;
|
|
377
|
+
/**
|
|
378
|
+
* @example
|
|
379
|
+
* ```ts
|
|
380
|
+
* [...new SortedMap<number, string>([[2, 'b'], [1, 'a']]).entries()]; // [[1, 'a'], [2, 'b']]
|
|
381
|
+
* ```
|
|
382
|
+
*/
|
|
383
|
+
entries(): IterableIterator<[K, V]>;
|
|
384
|
+
/**
|
|
385
|
+
* Iterates `[key, value]` pairs with keys in `[minKey, maxKey]`.
|
|
386
|
+
*
|
|
387
|
+
* @example
|
|
388
|
+
* ```ts
|
|
389
|
+
* const byPrice = new SortedMap<number, string>([[95, 'a'], [100, 'b'], [105, 'c']]);
|
|
390
|
+
* [...byPrice.irange(95, 100)]; // [[95, 'a'], [100, 'b']]
|
|
391
|
+
* ```
|
|
392
|
+
*/
|
|
393
|
+
irange(minKey?: K, maxKey?: K): IterableIterator<[K, V]>;
|
|
394
|
+
/**
|
|
395
|
+
* O(√n). Entry at ordinal position `index` in key order.
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* ```ts
|
|
399
|
+
* const byPrice = new SortedMap<number, string>([[2, 'b'], [1, 'a']]);
|
|
400
|
+
* byPrice.at(0); // [1, 'a']
|
|
401
|
+
* ```
|
|
402
|
+
*/
|
|
403
|
+
at(index: number): [K, V] | undefined;
|
|
404
|
+
/**
|
|
405
|
+
* @example
|
|
406
|
+
* ```ts
|
|
407
|
+
* new SortedMap<number, string>([[1, 'a'], [2, 'b']]).size; // 2
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
get size(): number;
|
|
411
|
+
/**
|
|
412
|
+
* @example
|
|
413
|
+
* ```ts
|
|
414
|
+
* const byPrice = new SortedMap<number, string>([[1, 'a']]);
|
|
415
|
+
* byPrice.clear();
|
|
416
|
+
* byPrice.size; // 0
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
419
|
+
clear(): void;
|
|
420
|
+
/**
|
|
421
|
+
* @example
|
|
422
|
+
* ```ts
|
|
423
|
+
* for (const [key, value] of new SortedMap([[2, 'b'], [1, 'a']])) {
|
|
424
|
+
* console.log(key, value); // 1 'a', then 2 'b'
|
|
425
|
+
* }
|
|
426
|
+
* ```
|
|
427
|
+
*/
|
|
428
|
+
[Symbol.iterator](): IterableIterator<[K, V]>;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
export { type Comparator, type NaturallyOrderable, SortedList, SortedMap, type SortedOptions, type SortedOptionsRequired, SortedSet };
|