data-structure-typed 2.4.4 → 2.5.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/CHANGELOG.md +22 -1
- package/README.md +34 -1
- package/dist/cjs/index.cjs +10639 -2151
- package/dist/cjs-legacy/index.cjs +10694 -2195
- package/dist/esm/index.mjs +10639 -2150
- package/dist/esm-legacy/index.mjs +10694 -2194
- package/dist/types/common/error.d.ts +23 -0
- package/dist/types/common/index.d.ts +1 -0
- package/dist/types/data-structures/base/iterable-element-base.d.ts +1 -1
- package/dist/types/data-structures/binary-tree/avl-tree.d.ts +128 -51
- package/dist/types/data-structures/binary-tree/binary-indexed-tree.d.ts +210 -164
- package/dist/types/data-structures/binary-tree/binary-tree.d.ts +439 -78
- package/dist/types/data-structures/binary-tree/bst.d.ts +311 -28
- package/dist/types/data-structures/binary-tree/red-black-tree.d.ts +217 -31
- package/dist/types/data-structures/binary-tree/segment-tree.d.ts +218 -152
- package/dist/types/data-structures/binary-tree/tree-map.d.ts +1281 -5
- package/dist/types/data-structures/binary-tree/tree-multi-map.d.ts +1087 -201
- package/dist/types/data-structures/binary-tree/tree-multi-set.d.ts +858 -65
- package/dist/types/data-structures/binary-tree/tree-set.d.ts +1133 -5
- package/dist/types/data-structures/graph/abstract-graph.d.ts +44 -0
- package/dist/types/data-structures/graph/directed-graph.d.ts +220 -47
- package/dist/types/data-structures/graph/map-graph.d.ts +59 -1
- package/dist/types/data-structures/graph/undirected-graph.d.ts +218 -59
- package/dist/types/data-structures/hash/hash-map.d.ts +230 -77
- package/dist/types/data-structures/heap/heap.d.ts +287 -99
- package/dist/types/data-structures/heap/max-heap.d.ts +46 -0
- package/dist/types/data-structures/heap/min-heap.d.ts +59 -0
- package/dist/types/data-structures/linked-list/doubly-linked-list.d.ts +286 -44
- package/dist/types/data-structures/linked-list/singly-linked-list.d.ts +278 -65
- package/dist/types/data-structures/linked-list/skip-linked-list.d.ts +415 -12
- package/dist/types/data-structures/matrix/matrix.d.ts +331 -0
- package/dist/types/data-structures/priority-queue/max-priority-queue.d.ts +57 -0
- package/dist/types/data-structures/priority-queue/min-priority-queue.d.ts +60 -0
- package/dist/types/data-structures/priority-queue/priority-queue.d.ts +60 -0
- package/dist/types/data-structures/queue/deque.d.ts +313 -66
- package/dist/types/data-structures/queue/queue.d.ts +211 -42
- package/dist/types/data-structures/stack/stack.d.ts +174 -32
- package/dist/types/data-structures/trie/trie.d.ts +213 -43
- package/dist/types/types/data-structures/binary-tree/segment-tree.d.ts +1 -1
- package/dist/types/types/data-structures/linked-list/skip-linked-list.d.ts +1 -4
- package/dist/types/types/data-structures/queue/deque.d.ts +6 -0
- package/dist/umd/data-structure-typed.js +10725 -2221
- package/dist/umd/data-structure-typed.min.js +4 -2
- package/package.json +5 -4
- package/src/common/error.ts +60 -0
- package/src/common/index.ts +2 -0
- package/src/data-structures/base/iterable-element-base.ts +2 -2
- package/src/data-structures/binary-tree/avl-tree.ts +146 -51
- package/src/data-structures/binary-tree/binary-indexed-tree.ts +317 -247
- package/src/data-structures/binary-tree/binary-tree.ts +567 -121
- package/src/data-structures/binary-tree/bst.ts +370 -37
- package/src/data-structures/binary-tree/red-black-tree.ts +328 -96
- package/src/data-structures/binary-tree/segment-tree.ts +378 -248
- package/src/data-structures/binary-tree/tree-map.ts +1411 -13
- package/src/data-structures/binary-tree/tree-multi-map.ts +1218 -215
- package/src/data-structures/binary-tree/tree-multi-set.ts +959 -69
- package/src/data-structures/binary-tree/tree-set.ts +1257 -15
- package/src/data-structures/graph/abstract-graph.ts +106 -1
- package/src/data-structures/graph/directed-graph.ts +233 -47
- package/src/data-structures/graph/map-graph.ts +59 -1
- package/src/data-structures/graph/undirected-graph.ts +308 -59
- package/src/data-structures/hash/hash-map.ts +254 -79
- package/src/data-structures/heap/heap.ts +305 -102
- package/src/data-structures/heap/max-heap.ts +48 -3
- package/src/data-structures/heap/min-heap.ts +59 -0
- package/src/data-structures/linked-list/doubly-linked-list.ts +303 -44
- package/src/data-structures/linked-list/singly-linked-list.ts +293 -65
- package/src/data-structures/linked-list/skip-linked-list.ts +707 -90
- package/src/data-structures/matrix/matrix.ts +433 -22
- package/src/data-structures/priority-queue/max-priority-queue.ts +59 -3
- package/src/data-structures/priority-queue/min-priority-queue.ts +60 -0
- package/src/data-structures/priority-queue/priority-queue.ts +60 -0
- package/src/data-structures/queue/deque.ts +358 -68
- package/src/data-structures/queue/queue.ts +223 -42
- package/src/data-structures/stack/stack.ts +184 -32
- package/src/data-structures/trie/trie.ts +227 -44
- package/src/types/data-structures/binary-tree/segment-tree.ts +1 -1
- package/src/types/data-structures/linked-list/skip-linked-list.ts +2 -1
- package/src/types/data-structures/queue/deque.ts +7 -0
- package/src/utils/utils.ts +4 -2
|
@@ -10,12 +10,18 @@
|
|
|
10
10
|
import type { Comparator } from '../../types';
|
|
11
11
|
import type { TreeMapEntryCallback, TreeMapOptions, TreeMapRangeOptions, TreeMapReduceCallback } from '../../types';
|
|
12
12
|
import { RedBlackTree } from './red-black-tree';
|
|
13
|
+
import { ERR } from '../../common';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* An ordered Map backed by a red-black tree.
|
|
16
17
|
*
|
|
17
18
|
* - Iteration order is ascending by key.
|
|
18
19
|
* - No node exposure: all APIs use keys/values only.
|
|
20
|
+
* @example
|
|
21
|
+
* // Set multiple key-value pairs
|
|
22
|
+
* const tm = new TreeMap<number, string>();
|
|
23
|
+
* tm.setMany([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
24
|
+
* console.log(tm.size); // 3;
|
|
19
25
|
*/
|
|
20
26
|
export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | undefined]> {
|
|
21
27
|
readonly #core: RedBlackTree<K, V>;
|
|
@@ -58,7 +64,7 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
58
64
|
} else {
|
|
59
65
|
// Validate entries like native Map: each item must be a 2-tuple-like value.
|
|
60
66
|
if (!Array.isArray(item) || item.length < 2) {
|
|
61
|
-
throw new TypeError('TreeMap
|
|
67
|
+
throw new TypeError(ERR.invalidEntry('TreeMap'));
|
|
62
68
|
}
|
|
63
69
|
k = item[0] as K;
|
|
64
70
|
v = item[1] as V | undefined;
|
|
@@ -81,7 +87,8 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
81
87
|
static createDefaultComparator<K>(): Comparator<K> {
|
|
82
88
|
return (a: K, b: K): number => {
|
|
83
89
|
if (typeof a === 'number' && typeof b === 'number') {
|
|
84
|
-
|
|
90
|
+
/* istanbul ignore next -- _validateKey prevents NaN from entering the tree */
|
|
91
|
+
if (Number.isNaN(a) || Number.isNaN(b)) throw new TypeError(ERR.invalidNaN('TreeMap'));
|
|
85
92
|
const aa = Object.is(a, -0) ? 0 : a;
|
|
86
93
|
const bb = Object.is(b, -0) ? 0 : b;
|
|
87
94
|
return aa > bb ? 1 : aa < bb ? -1 : 0;
|
|
@@ -94,11 +101,12 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
94
101
|
if (a instanceof Date && b instanceof Date) {
|
|
95
102
|
const ta = a.getTime();
|
|
96
103
|
const tb = b.getTime();
|
|
97
|
-
|
|
104
|
+
/* istanbul ignore next -- _validateKey prevents invalid Date from entering the tree */
|
|
105
|
+
if (Number.isNaN(ta) || Number.isNaN(tb)) throw new TypeError(ERR.invalidDate('TreeMap'));
|
|
98
106
|
return ta > tb ? 1 : ta < tb ? -1 : 0;
|
|
99
107
|
}
|
|
100
108
|
|
|
101
|
-
throw new TypeError('TreeMap
|
|
109
|
+
throw new TypeError(ERR.comparatorRequired('TreeMap'));
|
|
102
110
|
};
|
|
103
111
|
}
|
|
104
112
|
|
|
@@ -106,18 +114,18 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
106
114
|
if (!this.#isDefaultComparator) return;
|
|
107
115
|
|
|
108
116
|
if (typeof key === 'number') {
|
|
109
|
-
if (Number.isNaN(key)) throw new TypeError('TreeMap
|
|
117
|
+
if (Number.isNaN(key)) throw new TypeError(ERR.invalidNaN('TreeMap'));
|
|
110
118
|
return;
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
if (typeof key === 'string') return;
|
|
114
122
|
|
|
115
123
|
if (key instanceof Date) {
|
|
116
|
-
if (Number.isNaN(key.getTime())) throw new TypeError('TreeMap
|
|
124
|
+
if (Number.isNaN(key.getTime())) throw new TypeError(ERR.invalidDate('TreeMap'));
|
|
117
125
|
return;
|
|
118
126
|
}
|
|
119
127
|
|
|
120
|
-
throw new TypeError('TreeMap
|
|
128
|
+
throw new TypeError(ERR.comparatorRequired('TreeMap'));
|
|
121
129
|
}
|
|
122
130
|
|
|
123
131
|
/**
|
|
@@ -129,6 +137,52 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
129
137
|
|
|
130
138
|
/**
|
|
131
139
|
* Whether the map is empty.
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
* @example
|
|
184
|
+
* // Check empty
|
|
185
|
+
* console.log(new TreeMap().isEmpty()); // true;
|
|
132
186
|
*/
|
|
133
187
|
isEmpty(): boolean {
|
|
134
188
|
return this.size === 0;
|
|
@@ -137,6 +191,78 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
137
191
|
/**
|
|
138
192
|
* Set or overwrite a value for a key.
|
|
139
193
|
* @remarks Expected time O(log n)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
* @example
|
|
247
|
+
* // Sorted dictionary for a contact book
|
|
248
|
+
* const contacts = new TreeMap<string, string>([
|
|
249
|
+
* ['Bob', '555-0102'],
|
|
250
|
+
* ['Alice', '555-0101'],
|
|
251
|
+
* ['Charlie', '555-0103']
|
|
252
|
+
* ]);
|
|
253
|
+
*
|
|
254
|
+
* // Contacts are automatically sorted by name
|
|
255
|
+
* console.log([...contacts.keys()]); // ['Alice', 'Bob', 'Charlie'];
|
|
256
|
+
* console.log(contacts.get('Bob')); // '555-0102';
|
|
257
|
+
*
|
|
258
|
+
* // Find the first contact alphabetically after 'B'
|
|
259
|
+
* console.log(contacts.ceiling('B')); // ['Bob', '555-0102'];
|
|
260
|
+
*
|
|
261
|
+
* // Find contacts in range
|
|
262
|
+
* console.log(contacts.rangeSearch(['Alice', 'Bob'])); // [
|
|
263
|
+
* // ['Alice', '555-0101'],
|
|
264
|
+
* // ['Bob', '555-0102']
|
|
265
|
+
* // ];
|
|
140
266
|
*/
|
|
141
267
|
set(key: K, value: V | undefined): this {
|
|
142
268
|
this._validateKey(key);
|
|
@@ -147,6 +273,71 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
147
273
|
/**
|
|
148
274
|
* Get the value under a key.
|
|
149
275
|
* @remarks Expected time O(log n)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
* @example
|
|
331
|
+
* // Configuration registry with typed lookups
|
|
332
|
+
* const config = new TreeMap<string, number>([
|
|
333
|
+
* ['maxRetries', 3],
|
|
334
|
+
* ['timeout', 5000],
|
|
335
|
+
* ['poolSize', 10]
|
|
336
|
+
* ]);
|
|
337
|
+
*
|
|
338
|
+
* console.log(config.get('timeout')); // 5000;
|
|
339
|
+
* console.log(config.get('missing')); // undefined;
|
|
340
|
+
* console.log(config.size); // 3;
|
|
150
341
|
*/
|
|
151
342
|
get(key: K): V | undefined {
|
|
152
343
|
this._validateKey(key);
|
|
@@ -156,6 +347,70 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
156
347
|
/**
|
|
157
348
|
* Test whether a key exists.
|
|
158
349
|
* @remarks Expected time O(log n)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
* @example
|
|
405
|
+
* // Feature flag checking
|
|
406
|
+
* const flags = new TreeMap<string, boolean>([
|
|
407
|
+
* ['darkMode', true],
|
|
408
|
+
* ['betaFeature', false],
|
|
409
|
+
* ['notifications', true]
|
|
410
|
+
* ]);
|
|
411
|
+
*
|
|
412
|
+
* console.log(flags.has('darkMode')); // true;
|
|
413
|
+
* console.log(flags.has('unknownFlag')); // false;
|
|
159
414
|
*/
|
|
160
415
|
has(key: K): boolean {
|
|
161
416
|
this._validateKey(key);
|
|
@@ -166,6 +421,72 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
166
421
|
* Delete a key.
|
|
167
422
|
* @returns `true` if the key existed; otherwise `false`.
|
|
168
423
|
* @remarks Expected time O(log n)
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
* @example
|
|
479
|
+
* // Session management with expiry
|
|
480
|
+
* const sessions = new TreeMap<string, number>([
|
|
481
|
+
* ['sess_abc', Date.now()],
|
|
482
|
+
* ['sess_def', Date.now()],
|
|
483
|
+
* ['sess_ghi', Date.now()]
|
|
484
|
+
* ]);
|
|
485
|
+
*
|
|
486
|
+
* console.log(sessions.size); // 3;
|
|
487
|
+
* sessions.delete('sess_def');
|
|
488
|
+
* console.log(sessions.has('sess_def')); // false;
|
|
489
|
+
* console.log(sessions.size); // 2;
|
|
169
490
|
*/
|
|
170
491
|
delete(key: K): boolean {
|
|
171
492
|
this._validateKey(key);
|
|
@@ -175,6 +496,54 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
175
496
|
|
|
176
497
|
/**
|
|
177
498
|
* Remove all entries.
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
* @example
|
|
543
|
+
* // Remove all
|
|
544
|
+
* const tm = new TreeMap<number, string>([[1, 'a']]);
|
|
545
|
+
* tm.clear();
|
|
546
|
+
* console.log(tm.isEmpty()); // true;
|
|
178
547
|
*/
|
|
179
548
|
clear(): void {
|
|
180
549
|
this.#core.clear();
|
|
@@ -182,6 +551,53 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
182
551
|
|
|
183
552
|
/**
|
|
184
553
|
* Iterate over keys in ascending order.
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
* @example
|
|
598
|
+
* // Get sorted keys
|
|
599
|
+
* const tm = new TreeMap<number, string>([[3, 'c'], [1, 'a']]);
|
|
600
|
+
* console.log([...tm.keys()]); // [1, 3];
|
|
185
601
|
*/
|
|
186
602
|
keys(): IterableIterator<K> {
|
|
187
603
|
return this.#core.keys();
|
|
@@ -197,6 +613,53 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
197
613
|
* Iterate over values in ascending key order.
|
|
198
614
|
*
|
|
199
615
|
* Note: values may be `undefined` (TreeMap allows storing `undefined`, like native `Map`).
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
* @example
|
|
660
|
+
* // Get values in key order
|
|
661
|
+
* const tm = new TreeMap<number, string>([[2, 'b'], [1, 'a']]);
|
|
662
|
+
* console.log([...tm.values()]); // ['a', 'b'];
|
|
200
663
|
*/
|
|
201
664
|
*values(): IterableIterator<V | undefined> {
|
|
202
665
|
for (const k of this.keys()) yield this._entryFromKey(k)[1];
|
|
@@ -206,6 +669,53 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
206
669
|
* Iterate over `[key, value]` entries in ascending key order.
|
|
207
670
|
*
|
|
208
671
|
* Note: values may be `undefined`.
|
|
672
|
+
|
|
673
|
+
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
* @example
|
|
716
|
+
* // Iterate key-value pairs
|
|
717
|
+
* const tm = new TreeMap<number, string>([[3, 'c'], [1, 'a'], [2, 'b']]);
|
|
718
|
+
* console.log([...tm.entries()]); // [[1, 'a'], [2, 'b'], [3, 'c']];
|
|
209
719
|
*/
|
|
210
720
|
*entries(): IterableIterator<[K, V | undefined]> {
|
|
211
721
|
for (const k of this.keys()) yield this._entryFromKey(k);
|
|
@@ -219,6 +729,55 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
219
729
|
* Visit each entry in ascending key order.
|
|
220
730
|
*
|
|
221
731
|
* Note: callback value may be `undefined`.
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
|
|
742
|
+
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
* @example
|
|
776
|
+
* // Execute for each entry
|
|
777
|
+
* const tm = new TreeMap<number, string>([[1, 'a'], [2, 'b']]);
|
|
778
|
+
* const pairs: string[] = [];
|
|
779
|
+
* tm.forEach((v, k) => pairs.push(`${k}:${v}`));
|
|
780
|
+
* console.log(pairs); // ['1:a', '2:b'];
|
|
222
781
|
*/
|
|
223
782
|
forEach(cb: (value: V | undefined, key: K, map: TreeMap<K, V>) => void, thisArg?: any): void {
|
|
224
783
|
for (const [k, v] of this) cb.call(thisArg, v, k, this);
|
|
@@ -229,6 +788,54 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
229
788
|
*
|
|
230
789
|
* This mirrors `RedBlackTree.map`: mapping produces a new ordered container.
|
|
231
790
|
* @remarks Time O(n log n) expected, Space O(n)
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
|
|
808
|
+
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
|
|
813
|
+
|
|
814
|
+
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
|
|
833
|
+
|
|
834
|
+
* @example
|
|
835
|
+
* // Transform entries
|
|
836
|
+
* const tm = new TreeMap<number, number>([[1, 10], [2, 20]]);
|
|
837
|
+
* const doubled = tm.map((v, k) => [k, (v ?? 0) * 2] as [number, number]);
|
|
838
|
+
* console.log([...doubled.values()]); // [20, 40];
|
|
232
839
|
*/
|
|
233
840
|
map<MK, MV>(
|
|
234
841
|
callbackfn: TreeMapEntryCallback<K, V, [MK, MV], TreeMap<K, V>>,
|
|
@@ -249,6 +856,54 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
249
856
|
/**
|
|
250
857
|
* Create a new TreeMap containing only entries that satisfy the predicate.
|
|
251
858
|
* @remarks Time O(n log n) expected, Space O(n)
|
|
859
|
+
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
|
|
870
|
+
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
* @example
|
|
903
|
+
* // Filter entries
|
|
904
|
+
* const tm = new TreeMap<number, string>([[1, 'a'], [2, 'b'], [3, 'c']]);
|
|
905
|
+
* const filtered = tm.filter((v, k) => k > 1);
|
|
906
|
+
* console.log([...filtered.keys()]); // [2, 3];
|
|
252
907
|
*/
|
|
253
908
|
filter(callbackfn: TreeMapEntryCallback<K, V, boolean, TreeMap<K, V>>, thisArg?: unknown): TreeMap<K, V> {
|
|
254
909
|
const out = new TreeMap<K, V>([], { comparator: this.#userComparator });
|
|
@@ -265,6 +920,53 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
265
920
|
/**
|
|
266
921
|
* Reduce entries into a single accumulator.
|
|
267
922
|
* @remarks Time O(n), Space O(1)
|
|
923
|
+
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
|
|
927
|
+
|
|
928
|
+
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
|
|
937
|
+
|
|
938
|
+
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
|
|
951
|
+
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
|
|
957
|
+
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
|
|
962
|
+
|
|
963
|
+
|
|
964
|
+
|
|
965
|
+
|
|
966
|
+
* @example
|
|
967
|
+
* // Aggregate values
|
|
968
|
+
* const tm = new TreeMap<number, number>([[1, 10], [2, 20]]);
|
|
969
|
+
* console.log(tm.reduce((acc, v) => acc + (v ?? 0), 0)); // 30;
|
|
268
970
|
*/
|
|
269
971
|
reduce<A>(callbackfn: TreeMapReduceCallback<K, V, A, TreeMap<K, V>>, initialValue: A): A {
|
|
270
972
|
let acc = initialValue;
|
|
@@ -276,6 +978,51 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
276
978
|
/**
|
|
277
979
|
* Test whether all entries satisfy a predicate.
|
|
278
980
|
* @remarks Time O(n), Space O(1)
|
|
981
|
+
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
|
|
987
|
+
|
|
988
|
+
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
|
|
992
|
+
|
|
993
|
+
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
|
|
999
|
+
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
|
|
1007
|
+
|
|
1008
|
+
|
|
1009
|
+
|
|
1010
|
+
|
|
1011
|
+
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
|
|
1020
|
+
|
|
1021
|
+
|
|
1022
|
+
* @example
|
|
1023
|
+
* // Test all entries
|
|
1024
|
+
* const tm = new TreeMap<number, string>([[1, 'a'], [2, 'b']]);
|
|
1025
|
+
* console.log(tm.every((v, k) => k > 0)); // true;
|
|
279
1026
|
*/
|
|
280
1027
|
every(callbackfn: TreeMapEntryCallback<K, V, boolean, TreeMap<K, V>>, thisArg?: unknown): boolean {
|
|
281
1028
|
let index = 0;
|
|
@@ -291,6 +1038,51 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
291
1038
|
/**
|
|
292
1039
|
* Test whether any entry satisfies a predicate.
|
|
293
1040
|
* @remarks Time O(n), Space O(1)
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
|
|
1044
|
+
|
|
1045
|
+
|
|
1046
|
+
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
|
|
1052
|
+
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
|
|
1065
|
+
|
|
1066
|
+
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
|
|
1070
|
+
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
|
|
1080
|
+
|
|
1081
|
+
|
|
1082
|
+
* @example
|
|
1083
|
+
* // Test any entry
|
|
1084
|
+
* const tm = new TreeMap<number, string>([[1, 'a'], [2, 'b']]);
|
|
1085
|
+
* console.log(tm.some((v, k) => k === 2)); // true;
|
|
294
1086
|
*/
|
|
295
1087
|
some(callbackfn: TreeMapEntryCallback<K, V, boolean, TreeMap<K, V>>, thisArg?: unknown): boolean {
|
|
296
1088
|
let index = 0;
|
|
@@ -307,6 +1099,51 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
307
1099
|
* Find the first entry that satisfies a predicate.
|
|
308
1100
|
* @returns The first matching `[key, value]` tuple, or `undefined`.
|
|
309
1101
|
* @remarks Time O(n), Space O(1)
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
|
|
1110
|
+
|
|
1111
|
+
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
|
|
1115
|
+
|
|
1116
|
+
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
|
|
1126
|
+
|
|
1127
|
+
|
|
1128
|
+
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
|
|
1134
|
+
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
|
|
1139
|
+
|
|
1140
|
+
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
* @example
|
|
1144
|
+
* // Find matching entry
|
|
1145
|
+
* const tm = new TreeMap<number, string>([[1, 'a'], [2, 'b']]);
|
|
1146
|
+
* console.log(tm.find(v => v === 'b')?.[0]); // 2;
|
|
310
1147
|
*/
|
|
311
1148
|
find(callbackfn: TreeMapEntryCallback<K, V, boolean, TreeMap<K, V>>, thisArg?: unknown): [K, V | undefined] | undefined {
|
|
312
1149
|
let index = 0;
|
|
@@ -322,6 +1159,53 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
322
1159
|
/**
|
|
323
1160
|
* Materialize the map into an array of `[key, value]` tuples.
|
|
324
1161
|
* @remarks Time O(n), Space O(n)
|
|
1162
|
+
|
|
1163
|
+
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
|
|
1173
|
+
|
|
1174
|
+
|
|
1175
|
+
|
|
1176
|
+
|
|
1177
|
+
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
|
|
1183
|
+
|
|
1184
|
+
|
|
1185
|
+
|
|
1186
|
+
|
|
1187
|
+
|
|
1188
|
+
|
|
1189
|
+
|
|
1190
|
+
|
|
1191
|
+
|
|
1192
|
+
|
|
1193
|
+
|
|
1194
|
+
|
|
1195
|
+
|
|
1196
|
+
|
|
1197
|
+
|
|
1198
|
+
|
|
1199
|
+
|
|
1200
|
+
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
|
|
1204
|
+
|
|
1205
|
+
* @example
|
|
1206
|
+
* // Convert to array
|
|
1207
|
+
* const tm = new TreeMap<number, string>([[2, 'b'], [1, 'a']]);
|
|
1208
|
+
* console.log(tm.toArray()); // [[1, 'a'], [2, 'b']];
|
|
325
1209
|
*/
|
|
326
1210
|
toArray(): Array<[K, V | undefined]> {
|
|
327
1211
|
return [...this];
|
|
@@ -330,6 +1214,53 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
330
1214
|
/**
|
|
331
1215
|
* Print a human-friendly representation.
|
|
332
1216
|
* @remarks Time O(n), Space O(n)
|
|
1217
|
+
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
|
|
1223
|
+
|
|
1224
|
+
|
|
1225
|
+
|
|
1226
|
+
|
|
1227
|
+
|
|
1228
|
+
|
|
1229
|
+
|
|
1230
|
+
|
|
1231
|
+
|
|
1232
|
+
|
|
1233
|
+
|
|
1234
|
+
|
|
1235
|
+
|
|
1236
|
+
|
|
1237
|
+
|
|
1238
|
+
|
|
1239
|
+
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
|
|
1246
|
+
|
|
1247
|
+
|
|
1248
|
+
|
|
1249
|
+
|
|
1250
|
+
|
|
1251
|
+
|
|
1252
|
+
|
|
1253
|
+
|
|
1254
|
+
|
|
1255
|
+
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
* @example
|
|
1261
|
+
* // Display tree
|
|
1262
|
+
* const tm = new TreeMap<number, string>([[1, 'a']]);
|
|
1263
|
+
* expect(() => tm.print()).not.toThrow();
|
|
333
1264
|
*/
|
|
334
1265
|
print(): void {
|
|
335
1266
|
// Delegate to the underlying tree's visualization.
|
|
@@ -341,6 +1272,44 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
341
1272
|
|
|
342
1273
|
/**
|
|
343
1274
|
* Smallest entry by key.
|
|
1275
|
+
|
|
1276
|
+
|
|
1277
|
+
|
|
1278
|
+
|
|
1279
|
+
|
|
1280
|
+
|
|
1281
|
+
|
|
1282
|
+
|
|
1283
|
+
|
|
1284
|
+
|
|
1285
|
+
|
|
1286
|
+
|
|
1287
|
+
* @example
|
|
1288
|
+
* // Leaderboard with ranked scores
|
|
1289
|
+
* // Use score as key (descending), player name as value
|
|
1290
|
+
* const leaderboard = new TreeMap<number, string>([], {
|
|
1291
|
+
* comparator: (a, b) => b - a // descending
|
|
1292
|
+
* });
|
|
1293
|
+
*
|
|
1294
|
+
* leaderboard.set(1500, 'Alice');
|
|
1295
|
+
* leaderboard.set(2200, 'Bob');
|
|
1296
|
+
* leaderboard.set(1800, 'Charlie');
|
|
1297
|
+
* leaderboard.set(2500, 'Diana');
|
|
1298
|
+
*
|
|
1299
|
+
* // Top 3 players (first 3 in descending order)
|
|
1300
|
+
* const top3 = [...leaderboard.entries()].slice(0, 3);
|
|
1301
|
+
* console.log(top3); // [
|
|
1302
|
+
* // [2500, 'Diana'],
|
|
1303
|
+
* // [2200, 'Bob'],
|
|
1304
|
+
* // [1800, 'Charlie']
|
|
1305
|
+
* // ];
|
|
1306
|
+
*
|
|
1307
|
+
* // Highest scorer
|
|
1308
|
+
* console.log(leaderboard.first()); // [2500, 'Diana'];
|
|
1309
|
+
*
|
|
1310
|
+
* // Remove lowest scorer
|
|
1311
|
+
* console.log(leaderboard.pollLast()); // [1500, 'Alice'];
|
|
1312
|
+
* console.log(leaderboard.size); // 3;
|
|
344
1313
|
*/
|
|
345
1314
|
first(): [K, V | undefined] | undefined {
|
|
346
1315
|
const k = this.#core.getLeftMost();
|
|
@@ -349,6 +1318,28 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
349
1318
|
|
|
350
1319
|
/**
|
|
351
1320
|
* Largest entry by key.
|
|
1321
|
+
|
|
1322
|
+
|
|
1323
|
+
|
|
1324
|
+
|
|
1325
|
+
|
|
1326
|
+
|
|
1327
|
+
|
|
1328
|
+
|
|
1329
|
+
|
|
1330
|
+
|
|
1331
|
+
|
|
1332
|
+
|
|
1333
|
+
* @example
|
|
1334
|
+
* // Access the maximum entry
|
|
1335
|
+
* const scores = new TreeMap<number, string>([
|
|
1336
|
+
* [85, 'Bob'],
|
|
1337
|
+
* [92, 'Alice'],
|
|
1338
|
+
* [78, 'Charlie']
|
|
1339
|
+
* ]);
|
|
1340
|
+
*
|
|
1341
|
+
* console.log(scores.last()); // [92, 'Alice'];
|
|
1342
|
+
* console.log(scores.first()); // [78, 'Charlie'];
|
|
352
1343
|
*/
|
|
353
1344
|
last(): [K, V | undefined] | undefined {
|
|
354
1345
|
const k = this.#core.getRightMost();
|
|
@@ -357,6 +1348,30 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
357
1348
|
|
|
358
1349
|
/**
|
|
359
1350
|
* Remove and return the smallest entry.
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
|
|
1354
|
+
|
|
1355
|
+
|
|
1356
|
+
|
|
1357
|
+
|
|
1358
|
+
|
|
1359
|
+
|
|
1360
|
+
|
|
1361
|
+
|
|
1362
|
+
|
|
1363
|
+
* @example
|
|
1364
|
+
* // Process items from lowest priority
|
|
1365
|
+
* const tasks = new TreeMap<number, string>([
|
|
1366
|
+
* [3, 'Low'],
|
|
1367
|
+
* [1, 'Critical'],
|
|
1368
|
+
* [2, 'Medium']
|
|
1369
|
+
* ]);
|
|
1370
|
+
*
|
|
1371
|
+
* // Process lowest priority first
|
|
1372
|
+
* console.log(tasks.pollFirst()); // [1, 'Critical'];
|
|
1373
|
+
* console.log(tasks.pollFirst()); // [2, 'Medium'];
|
|
1374
|
+
* console.log(tasks.size); // 1;
|
|
360
1375
|
*/
|
|
361
1376
|
pollFirst(): [K, V | undefined] | undefined {
|
|
362
1377
|
const entry = this.first();
|
|
@@ -367,6 +1382,30 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
367
1382
|
|
|
368
1383
|
/**
|
|
369
1384
|
* Remove and return the largest entry.
|
|
1385
|
+
|
|
1386
|
+
|
|
1387
|
+
|
|
1388
|
+
|
|
1389
|
+
|
|
1390
|
+
|
|
1391
|
+
|
|
1392
|
+
|
|
1393
|
+
|
|
1394
|
+
|
|
1395
|
+
|
|
1396
|
+
|
|
1397
|
+
* @example
|
|
1398
|
+
* // Remove the maximum entry
|
|
1399
|
+
* const bids = new TreeMap<number, string>([
|
|
1400
|
+
* [100, 'Alice'],
|
|
1401
|
+
* [150, 'Bob'],
|
|
1402
|
+
* [120, 'Charlie']
|
|
1403
|
+
* ]);
|
|
1404
|
+
*
|
|
1405
|
+
* // Remove highest bid
|
|
1406
|
+
* console.log(bids.pollLast()); // [150, 'Bob'];
|
|
1407
|
+
* console.log(bids.size); // 2;
|
|
1408
|
+
* console.log(bids.last()); // [120, 'Charlie'];
|
|
370
1409
|
*/
|
|
371
1410
|
pollLast(): [K, V | undefined] | undefined {
|
|
372
1411
|
const entry = this.last();
|
|
@@ -377,6 +1416,79 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
377
1416
|
|
|
378
1417
|
/**
|
|
379
1418
|
* Smallest entry whose key is >= the given key.
|
|
1419
|
+
|
|
1420
|
+
|
|
1421
|
+
|
|
1422
|
+
|
|
1423
|
+
|
|
1424
|
+
|
|
1425
|
+
|
|
1426
|
+
|
|
1427
|
+
|
|
1428
|
+
|
|
1429
|
+
|
|
1430
|
+
|
|
1431
|
+
|
|
1432
|
+
|
|
1433
|
+
|
|
1434
|
+
|
|
1435
|
+
|
|
1436
|
+
|
|
1437
|
+
|
|
1438
|
+
|
|
1439
|
+
|
|
1440
|
+
|
|
1441
|
+
|
|
1442
|
+
|
|
1443
|
+
|
|
1444
|
+
|
|
1445
|
+
|
|
1446
|
+
|
|
1447
|
+
|
|
1448
|
+
|
|
1449
|
+
|
|
1450
|
+
|
|
1451
|
+
|
|
1452
|
+
|
|
1453
|
+
|
|
1454
|
+
|
|
1455
|
+
|
|
1456
|
+
|
|
1457
|
+
|
|
1458
|
+
|
|
1459
|
+
|
|
1460
|
+
|
|
1461
|
+
* @example
|
|
1462
|
+
* // Event scheduler with time-based lookup
|
|
1463
|
+
* const events = new TreeMap<Date, string>();
|
|
1464
|
+
*
|
|
1465
|
+
* const meeting = new Date('2024-01-15T10:00:00Z');
|
|
1466
|
+
* const lunch = new Date('2024-01-15T12:00:00Z');
|
|
1467
|
+
* const review = new Date('2024-01-15T15:00:00Z');
|
|
1468
|
+
* const standup = new Date('2024-01-15T09:00:00Z');
|
|
1469
|
+
*
|
|
1470
|
+
* events.set(meeting, 'Team Meeting');
|
|
1471
|
+
* events.set(lunch, 'Lunch Break');
|
|
1472
|
+
* events.set(review, 'Code Review');
|
|
1473
|
+
* events.set(standup, 'Daily Standup');
|
|
1474
|
+
*
|
|
1475
|
+
* // Events are sorted chronologically
|
|
1476
|
+
* console.log([...events.values()]); // [
|
|
1477
|
+
* // 'Daily Standup',
|
|
1478
|
+
* // 'Team Meeting',
|
|
1479
|
+
* // 'Lunch Break',
|
|
1480
|
+
* // 'Code Review'
|
|
1481
|
+
* // ];
|
|
1482
|
+
*
|
|
1483
|
+
* // Next event after 11:00
|
|
1484
|
+
* const after11 = new Date('2024-01-15T11:00:00Z');
|
|
1485
|
+
* console.log(events.ceiling(after11)?.[1]); // 'Lunch Break';
|
|
1486
|
+
*
|
|
1487
|
+
* // Events between 9:30 and 13:00
|
|
1488
|
+
* const from = new Date('2024-01-15T09:30:00Z');
|
|
1489
|
+
* const to = new Date('2024-01-15T13:00:00Z');
|
|
1490
|
+
* const window = events.rangeSearch([from, to]);
|
|
1491
|
+
* console.log(window.map(([, v]) => v)); // ['Team Meeting', 'Lunch Break'];
|
|
380
1492
|
*/
|
|
381
1493
|
ceiling(key: K): [K, V | undefined] | undefined {
|
|
382
1494
|
this._validateKey(key);
|
|
@@ -386,6 +1498,63 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
386
1498
|
|
|
387
1499
|
/**
|
|
388
1500
|
* Largest entry whose key is <= the given key.
|
|
1501
|
+
|
|
1502
|
+
|
|
1503
|
+
|
|
1504
|
+
|
|
1505
|
+
|
|
1506
|
+
|
|
1507
|
+
|
|
1508
|
+
|
|
1509
|
+
|
|
1510
|
+
|
|
1511
|
+
|
|
1512
|
+
|
|
1513
|
+
|
|
1514
|
+
|
|
1515
|
+
|
|
1516
|
+
|
|
1517
|
+
|
|
1518
|
+
|
|
1519
|
+
|
|
1520
|
+
|
|
1521
|
+
|
|
1522
|
+
|
|
1523
|
+
|
|
1524
|
+
|
|
1525
|
+
|
|
1526
|
+
|
|
1527
|
+
|
|
1528
|
+
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
|
|
1532
|
+
|
|
1533
|
+
|
|
1534
|
+
|
|
1535
|
+
|
|
1536
|
+
|
|
1537
|
+
|
|
1538
|
+
|
|
1539
|
+
|
|
1540
|
+
|
|
1541
|
+
|
|
1542
|
+
|
|
1543
|
+
* @example
|
|
1544
|
+
* // Find the largest key ≤ target
|
|
1545
|
+
* const versions = new TreeMap<number, string>([
|
|
1546
|
+
* [1, 'v1.0'],
|
|
1547
|
+
* [3, 'v3.0'],
|
|
1548
|
+
* [5, 'v5.0'],
|
|
1549
|
+
* [7, 'v7.0']
|
|
1550
|
+
* ]);
|
|
1551
|
+
*
|
|
1552
|
+
* // Largest version ≤ 4
|
|
1553
|
+
* console.log(versions.floor(4)); // [3, 'v3.0'];
|
|
1554
|
+
* // Largest version ≤ 5 (exact match)
|
|
1555
|
+
* console.log(versions.floor(5)); // [5, 'v5.0'];
|
|
1556
|
+
* // No version ≤ 0
|
|
1557
|
+
* console.log(versions.floor(0)); // undefined;
|
|
389
1558
|
*/
|
|
390
1559
|
floor(key: K): [K, V | undefined] | undefined {
|
|
391
1560
|
this._validateKey(key);
|
|
@@ -395,6 +1564,63 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
395
1564
|
|
|
396
1565
|
/**
|
|
397
1566
|
* Smallest entry whose key is > the given key.
|
|
1567
|
+
|
|
1568
|
+
|
|
1569
|
+
|
|
1570
|
+
|
|
1571
|
+
|
|
1572
|
+
|
|
1573
|
+
|
|
1574
|
+
|
|
1575
|
+
|
|
1576
|
+
|
|
1577
|
+
|
|
1578
|
+
|
|
1579
|
+
|
|
1580
|
+
|
|
1581
|
+
|
|
1582
|
+
|
|
1583
|
+
|
|
1584
|
+
|
|
1585
|
+
|
|
1586
|
+
|
|
1587
|
+
|
|
1588
|
+
|
|
1589
|
+
|
|
1590
|
+
|
|
1591
|
+
|
|
1592
|
+
|
|
1593
|
+
|
|
1594
|
+
|
|
1595
|
+
|
|
1596
|
+
|
|
1597
|
+
|
|
1598
|
+
|
|
1599
|
+
|
|
1600
|
+
|
|
1601
|
+
|
|
1602
|
+
|
|
1603
|
+
|
|
1604
|
+
|
|
1605
|
+
|
|
1606
|
+
|
|
1607
|
+
|
|
1608
|
+
|
|
1609
|
+
* @example
|
|
1610
|
+
* // Find the smallest key strictly > target
|
|
1611
|
+
* const prices = new TreeMap<number, string>([
|
|
1612
|
+
* [10, 'Basic'],
|
|
1613
|
+
* [25, 'Standard'],
|
|
1614
|
+
* [50, 'Premium'],
|
|
1615
|
+
* [100, 'Enterprise']
|
|
1616
|
+
* ]);
|
|
1617
|
+
*
|
|
1618
|
+
* // Next tier above $25
|
|
1619
|
+
* console.log(prices.higher(25)); // [50, 'Premium'];
|
|
1620
|
+
* // Next tier above $99
|
|
1621
|
+
* console.log(prices.higher(99)); // [100, 'Enterprise'];
|
|
1622
|
+
* // Nothing above $100
|
|
1623
|
+
* console.log(prices.higher(100)); // undefined;
|
|
398
1624
|
*/
|
|
399
1625
|
higher(key: K): [K, V | undefined] | undefined {
|
|
400
1626
|
this._validateKey(key);
|
|
@@ -404,6 +1630,61 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
404
1630
|
|
|
405
1631
|
/**
|
|
406
1632
|
* Largest entry whose key is < the given key.
|
|
1633
|
+
|
|
1634
|
+
|
|
1635
|
+
|
|
1636
|
+
|
|
1637
|
+
|
|
1638
|
+
|
|
1639
|
+
|
|
1640
|
+
|
|
1641
|
+
|
|
1642
|
+
|
|
1643
|
+
|
|
1644
|
+
|
|
1645
|
+
|
|
1646
|
+
|
|
1647
|
+
|
|
1648
|
+
|
|
1649
|
+
|
|
1650
|
+
|
|
1651
|
+
|
|
1652
|
+
|
|
1653
|
+
|
|
1654
|
+
|
|
1655
|
+
|
|
1656
|
+
|
|
1657
|
+
|
|
1658
|
+
|
|
1659
|
+
|
|
1660
|
+
|
|
1661
|
+
|
|
1662
|
+
|
|
1663
|
+
|
|
1664
|
+
|
|
1665
|
+
|
|
1666
|
+
|
|
1667
|
+
|
|
1668
|
+
|
|
1669
|
+
|
|
1670
|
+
|
|
1671
|
+
|
|
1672
|
+
|
|
1673
|
+
|
|
1674
|
+
|
|
1675
|
+
* @example
|
|
1676
|
+
* // Find the largest key strictly < target
|
|
1677
|
+
* const temps = new TreeMap<number, string>([
|
|
1678
|
+
* [0, 'Freezing'],
|
|
1679
|
+
* [20, 'Cool'],
|
|
1680
|
+
* [30, 'Warm'],
|
|
1681
|
+
* [40, 'Hot']
|
|
1682
|
+
* ]);
|
|
1683
|
+
*
|
|
1684
|
+
* // Largest reading below 30
|
|
1685
|
+
* console.log(temps.lower(30)); // [20, 'Cool'];
|
|
1686
|
+
* // Nothing below 0
|
|
1687
|
+
* console.log(temps.lower(0)); // undefined;
|
|
407
1688
|
*/
|
|
408
1689
|
lower(key: K): [K, V | undefined] | undefined {
|
|
409
1690
|
this._validateKey(key);
|
|
@@ -416,6 +1697,78 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
416
1697
|
*
|
|
417
1698
|
* @param range `[low, high]`
|
|
418
1699
|
* @param options Inclusive/exclusive bounds (defaults to inclusive).
|
|
1700
|
+
|
|
1701
|
+
|
|
1702
|
+
|
|
1703
|
+
|
|
1704
|
+
|
|
1705
|
+
|
|
1706
|
+
|
|
1707
|
+
|
|
1708
|
+
|
|
1709
|
+
|
|
1710
|
+
|
|
1711
|
+
|
|
1712
|
+
|
|
1713
|
+
|
|
1714
|
+
|
|
1715
|
+
|
|
1716
|
+
|
|
1717
|
+
|
|
1718
|
+
|
|
1719
|
+
|
|
1720
|
+
|
|
1721
|
+
|
|
1722
|
+
|
|
1723
|
+
|
|
1724
|
+
|
|
1725
|
+
|
|
1726
|
+
|
|
1727
|
+
|
|
1728
|
+
|
|
1729
|
+
|
|
1730
|
+
|
|
1731
|
+
|
|
1732
|
+
|
|
1733
|
+
|
|
1734
|
+
|
|
1735
|
+
|
|
1736
|
+
|
|
1737
|
+
|
|
1738
|
+
|
|
1739
|
+
|
|
1740
|
+
|
|
1741
|
+
|
|
1742
|
+
* @example
|
|
1743
|
+
* // Inventory system with price-sorted products
|
|
1744
|
+
* interface Product {
|
|
1745
|
+
* name: string;
|
|
1746
|
+
* price: number;
|
|
1747
|
+
* stock: number;
|
|
1748
|
+
* }
|
|
1749
|
+
*
|
|
1750
|
+
* const inventory = new TreeMap<string, Product, Product>(
|
|
1751
|
+
* [
|
|
1752
|
+
* { name: 'Widget', price: 9.99, stock: 100 },
|
|
1753
|
+
* { name: 'Gadget', price: 24.99, stock: 50 },
|
|
1754
|
+
* { name: 'Doohickey', price: 4.99, stock: 200 }
|
|
1755
|
+
* ],
|
|
1756
|
+
* { toEntryFn: p => [p.name, p] }
|
|
1757
|
+
* );
|
|
1758
|
+
*
|
|
1759
|
+
* // Sorted alphabetically by product name
|
|
1760
|
+
* console.log([...inventory.keys()]); // ['Doohickey', 'Gadget', 'Widget'];
|
|
1761
|
+
*
|
|
1762
|
+
* // Filter high-stock items
|
|
1763
|
+
* const highStock = inventory.filter(p => (p?.stock ?? 0) > 75);
|
|
1764
|
+
* console.log([...highStock.keys()]); // ['Doohickey', 'Widget'];
|
|
1765
|
+
*
|
|
1766
|
+
* // Calculate total inventory value
|
|
1767
|
+
* const totalValue = inventory.reduce(
|
|
1768
|
+
* (sum, p) => sum + (p ? p.price * p.stock : 0),
|
|
1769
|
+
* 0
|
|
1770
|
+
* );
|
|
1771
|
+
* console.log(totalValue); // toBeCloseTo;
|
|
419
1772
|
*/
|
|
420
1773
|
rangeSearch(range: [K, K], options: TreeMapRangeOptions = {}): Array<[K, V | undefined]> {
|
|
421
1774
|
const { lowInclusive = true, highInclusive = true } = options;
|
|
@@ -428,7 +1781,7 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
428
1781
|
const cmp = this.#core.comparator;
|
|
429
1782
|
|
|
430
1783
|
for (const k of keys) {
|
|
431
|
-
if (k === undefined) continue;
|
|
1784
|
+
/* istanbul ignore next -- defensive: tree keys are never undefined */ if (k === undefined) continue;
|
|
432
1785
|
if (!lowInclusive && cmp(k, low) === 0) continue;
|
|
433
1786
|
if (!highInclusive && cmp(k, high) === 0) continue;
|
|
434
1787
|
out.push(this._entryFromKey(k));
|
|
@@ -440,11 +1793,56 @@ export class TreeMap<K = any, V = any, R = [K, V]> implements Iterable<[K, V | u
|
|
|
440
1793
|
/**
|
|
441
1794
|
* Creates a shallow clone of this map.
|
|
442
1795
|
* @remarks Time O(n log n), Space O(n)
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
1796
|
+
|
|
1797
|
+
|
|
1798
|
+
|
|
1799
|
+
|
|
1800
|
+
|
|
1801
|
+
|
|
1802
|
+
|
|
1803
|
+
|
|
1804
|
+
|
|
1805
|
+
|
|
1806
|
+
|
|
1807
|
+
|
|
1808
|
+
|
|
1809
|
+
|
|
1810
|
+
|
|
1811
|
+
|
|
1812
|
+
|
|
1813
|
+
|
|
1814
|
+
|
|
1815
|
+
|
|
1816
|
+
|
|
1817
|
+
|
|
1818
|
+
|
|
1819
|
+
|
|
1820
|
+
|
|
1821
|
+
|
|
1822
|
+
|
|
1823
|
+
|
|
1824
|
+
|
|
1825
|
+
|
|
1826
|
+
|
|
1827
|
+
|
|
1828
|
+
|
|
1829
|
+
|
|
1830
|
+
|
|
1831
|
+
|
|
1832
|
+
|
|
1833
|
+
|
|
1834
|
+
|
|
1835
|
+
|
|
1836
|
+
|
|
1837
|
+
|
|
1838
|
+
|
|
1839
|
+
|
|
1840
|
+
* @example
|
|
1841
|
+
* // Deep clone
|
|
1842
|
+
* const tm = new TreeMap<number, string>([[1, 'a'], [2, 'b']]);
|
|
1843
|
+
* const copy = tm.clone();
|
|
1844
|
+
* copy.delete(1);
|
|
1845
|
+
* console.log(tm.has(1)); // true;
|
|
448
1846
|
*/
|
|
449
1847
|
clone(): TreeMap<K, V> {
|
|
450
1848
|
return new TreeMap<K, V>(this, {
|