@byloth/core 2.0.0-rc.9 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core.js +4087 -621
- package/dist/core.js.map +1 -1
- package/dist/core.umd.cjs +2 -2
- package/dist/core.umd.cjs.map +1 -1
- package/package.json +17 -13
- package/src/core/types.ts +41 -0
- package/src/helpers.ts +11 -2
- package/src/index.ts +12 -9
- package/src/models/aggregators/aggregated-async-iterator.ts +920 -21
- package/src/models/aggregators/aggregated-iterator.ts +838 -22
- package/src/models/aggregators/reduced-iterator.ts +827 -11
- package/src/models/aggregators/types.ts +153 -10
- package/src/models/callbacks/callable-object.ts +42 -6
- package/src/models/callbacks/index.ts +2 -2
- package/src/models/callbacks/publisher.ts +160 -4
- package/src/models/callbacks/switchable-callback.ts +230 -23
- package/src/models/callbacks/types.ts +16 -0
- package/src/models/exceptions/core.ts +132 -3
- package/src/models/exceptions/index.ts +405 -13
- package/src/models/index.ts +4 -8
- package/src/models/iterators/smart-async-iterator.ts +827 -22
- package/src/models/iterators/smart-iterator.ts +755 -20
- package/src/models/iterators/types.ts +268 -9
- package/src/models/json/json-storage.ts +508 -110
- package/src/models/json/types.ts +10 -1
- package/src/models/promises/deferred-promise.ts +85 -5
- package/src/models/promises/index.ts +1 -3
- package/src/models/promises/smart-promise.ts +272 -4
- package/src/models/promises/timed-promise.ts +43 -1
- package/src/models/promises/types.ts +84 -2
- package/src/models/timers/clock.ts +109 -19
- package/src/models/timers/countdown.ts +176 -21
- package/src/models/timers/game-loop.ts +266 -0
- package/src/models/timers/index.ts +2 -1
- package/src/models/types.ts +6 -5
- package/src/utils/async.ts +43 -0
- package/src/utils/curve.ts +85 -0
- package/src/utils/date.ts +204 -10
- package/src/utils/dom.ts +16 -2
- package/src/utils/index.ts +3 -2
- package/src/utils/iterator.ts +200 -17
- package/src/utils/math.ts +55 -3
- package/src/utils/random.ts +139 -2
- package/src/utils/string.ts +11 -0
- package/src/models/game-loop.ts +0 -83
- package/src/models/promises/long-running-task.ts +0 -294
- package/src/models/promises/thenable.ts +0 -97
|
@@ -9,24 +9,232 @@ import type {
|
|
|
9
9
|
import type { MaybePromise } from "../types.js";
|
|
10
10
|
|
|
11
11
|
import ReducedIterator from "./reduced-iterator.js";
|
|
12
|
-
import type { MaybeAsyncKeyedIteratee,
|
|
13
|
-
|
|
12
|
+
import type { MaybeAsyncKeyedIteratee, MaybeAsyncKeyedReducer } from "./types.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* A class representing an iterator that aggregates elements in a lazy and optimized way.
|
|
16
|
+
*
|
|
17
|
+
* It's part of the {@link SmartAsyncIterator} implementation,
|
|
18
|
+
* providing a way to group elements of an iterable by key.
|
|
19
|
+
* For this reason, it isn't recommended to instantiate this class directly
|
|
20
|
+
* (although it's still possible), but rather use the {@link SmartAsyncIterator.groupBy} method.
|
|
21
|
+
*
|
|
22
|
+
* It isn't directly iterable like its parent class but rather needs to specify on what you want to iterate.
|
|
23
|
+
* See the {@link AggregatedAsyncIterator.keys}, {@link AggregatedAsyncIterator.entries}
|
|
24
|
+
* & {@link AggregatedAsyncIterator.values} methods.
|
|
25
|
+
* It does, however, provide the same set of methods to perform
|
|
26
|
+
* operations and transformations on the elements of the iterator,
|
|
27
|
+
* having also the knowledge and context of the groups to which
|
|
28
|
+
* they belong, allowing to handle them in a grouped manner.
|
|
29
|
+
*
|
|
30
|
+
* This is particularly useful when you need to group elements and
|
|
31
|
+
* then perform specific operations on the groups themselves.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* const elements = fetch([...]); // Promise<[-3, -1, 0, 2, 3, 5, 6, 8]>;
|
|
35
|
+
* const results = new SmartAsyncIterator(elements)
|
|
36
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
37
|
+
* .count();
|
|
38
|
+
*
|
|
39
|
+
* console.log(await results.toObject()); // { odd: 4, even: 4 }
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @template K The type of the keys used to group the elements.
|
|
43
|
+
* @template T The type of the elements to aggregate.
|
|
44
|
+
*/
|
|
14
45
|
export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
15
46
|
{
|
|
47
|
+
/**
|
|
48
|
+
* The internal {@link SmartAsyncIterator} object that holds the elements to aggregate.
|
|
49
|
+
*/
|
|
16
50
|
protected _elements: SmartAsyncIterator<[K, T]>;
|
|
17
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Initializes a new instance of the {@link AggregatedAsyncIterator} class.
|
|
54
|
+
*
|
|
55
|
+
* ---
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const iterator = new AggregatedAsyncIterator<string, number>([["A", 1], ["B", 2], ["A", 3], ["C", 4], ["B", 5]]);
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* ---
|
|
63
|
+
*
|
|
64
|
+
* @param iterable The iterable to aggregate.
|
|
65
|
+
*/
|
|
18
66
|
public constructor(iterable: Iterable<[K, T]>);
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Initializes a new instance of the {@link AggregatedAsyncIterator} class.
|
|
70
|
+
*
|
|
71
|
+
* ---
|
|
72
|
+
*
|
|
73
|
+
* @example
|
|
74
|
+
* ```ts
|
|
75
|
+
* const elements = fetch([...]); // Promise<[["A", 1], ["B", 2], ["A", 3], ["C", 4], ["B", 5]]>
|
|
76
|
+
* const iterator = new AggregatedAsyncIterator<string, number>(elements);
|
|
77
|
+
* ```
|
|
78
|
+
*
|
|
79
|
+
* ---
|
|
80
|
+
*
|
|
81
|
+
* @param iterable The iterable to aggregate.
|
|
82
|
+
*/
|
|
19
83
|
public constructor(iterable: AsyncIterable<[K, T]>);
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Initializes a new instance of the {@link AggregatedAsyncIterator} class.
|
|
87
|
+
*
|
|
88
|
+
* ---
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* import { Random } from "@byloth/core";
|
|
93
|
+
*
|
|
94
|
+
* const iterator = new AggregatedAsyncIterator<string, number>({
|
|
95
|
+
* _index: 0,
|
|
96
|
+
* next: () =>
|
|
97
|
+
* {
|
|
98
|
+
* if (this._index >= 5) { return { done: true, value: undefined }; }
|
|
99
|
+
* this._index += 1;
|
|
100
|
+
*
|
|
101
|
+
* return { done: false, value: [Random.Choice(["A", "B", "C"]), (this._index + 1)] };
|
|
102
|
+
* }
|
|
103
|
+
* });
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* ---
|
|
107
|
+
*
|
|
108
|
+
* @param iterator The iterator to aggregate.
|
|
109
|
+
*/
|
|
20
110
|
public constructor(iterator: Iterator<[K, T]>);
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Initializes a new instance of the {@link AggregatedAsyncIterator} class.
|
|
114
|
+
*
|
|
115
|
+
* ---
|
|
116
|
+
*
|
|
117
|
+
* @example
|
|
118
|
+
* ```ts
|
|
119
|
+
* import { Random } from "@byloth/core";
|
|
120
|
+
*
|
|
121
|
+
* const iterator = new AggregatedAsyncIterator<string, number>({
|
|
122
|
+
* _index: 0,
|
|
123
|
+
* next: async () =>
|
|
124
|
+
* {
|
|
125
|
+
* if (this._index >= 5) { return { done: true, value: undefined }; }
|
|
126
|
+
* this._index += 1;
|
|
127
|
+
*
|
|
128
|
+
* return { done: false, value: [Random.Choice(["A", "B", "C"]), (this._index + 1)] };
|
|
129
|
+
* }
|
|
130
|
+
* });
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* ---
|
|
134
|
+
*
|
|
135
|
+
* @param iterator The iterator to aggregate.
|
|
136
|
+
*/
|
|
21
137
|
public constructor(iterator: AsyncIterator<[K, T]>);
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Initializes a new instance of the {@link AggregatedAsyncIterator} class.
|
|
141
|
+
*
|
|
142
|
+
* ---
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* import { range, Random } from "@byloth/core";
|
|
147
|
+
*
|
|
148
|
+
* const iterator = new AggregatedAsyncIterator<string, number>(function* ()
|
|
149
|
+
* {
|
|
150
|
+
* for (const index of range(5))
|
|
151
|
+
* {
|
|
152
|
+
* yield [Random.Choice(["A", "B", "C"]), (index + 1)];
|
|
153
|
+
* }
|
|
154
|
+
* });
|
|
155
|
+
* ```
|
|
156
|
+
*
|
|
157
|
+
* ---
|
|
158
|
+
*
|
|
159
|
+
* @param generatorFn The generator function to aggregate.
|
|
160
|
+
*/
|
|
22
161
|
public constructor(generatorFn: GeneratorFunction<[K, T]>);
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Initializes a new instance of the {@link AggregatedAsyncIterator} class.
|
|
165
|
+
*
|
|
166
|
+
* ---
|
|
167
|
+
*
|
|
168
|
+
* @example
|
|
169
|
+
* ```ts
|
|
170
|
+
* import { range, Random } from "@byloth/core";
|
|
171
|
+
*
|
|
172
|
+
* const iterator = new AggregatedAsyncIterator<string, number>(async function* ()
|
|
173
|
+
* {
|
|
174
|
+
* for await (const index of range(5))
|
|
175
|
+
* {
|
|
176
|
+
* yield [Random.Choice(["A", "B", "C"]), (index + 1)];
|
|
177
|
+
* }
|
|
178
|
+
* });
|
|
179
|
+
* ```
|
|
180
|
+
*
|
|
181
|
+
* ---
|
|
182
|
+
*
|
|
183
|
+
* @param generatorFn The generator function to aggregate.
|
|
184
|
+
*/
|
|
23
185
|
public constructor(generatorFn: AsyncGeneratorFunction<[K, T]>);
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Initializes a new instance of the {@link AggregatedAsyncIterator} class.
|
|
189
|
+
*
|
|
190
|
+
* ---
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```ts
|
|
194
|
+
* const iterator = new AggregatedAsyncIterator(asyncKeyedValues);
|
|
195
|
+
* ```
|
|
196
|
+
*
|
|
197
|
+
* ---
|
|
198
|
+
*
|
|
199
|
+
* @param argument The iterable, iterator or generator function to aggregate.
|
|
200
|
+
*/
|
|
24
201
|
public constructor(argument: MaybeAsyncIteratorLike<[K, T]> | MaybeAsyncGeneratorFunction<[K, T]>);
|
|
25
202
|
public constructor(argument: MaybeAsyncIteratorLike<[K, T]> | MaybeAsyncGeneratorFunction<[K, T]>)
|
|
26
203
|
{
|
|
27
204
|
this._elements = new SmartAsyncIterator(argument);
|
|
28
205
|
}
|
|
29
206
|
|
|
207
|
+
/**
|
|
208
|
+
* Determines whether all elements of each group of the iterator satisfy a given condition.
|
|
209
|
+
* See also {@link AggregatedAsyncIterator.some}.
|
|
210
|
+
* This method will consume the entire iterator in the process.
|
|
211
|
+
*
|
|
212
|
+
* It will iterate over all elements of the iterator checjing if they satisfy the condition.
|
|
213
|
+
* Once a single element of one group doesn't satisfy the condition,
|
|
214
|
+
* the result for the respective group will be `false`.
|
|
215
|
+
*
|
|
216
|
+
* Eventually, it will return a new {@link ReducedIterator}
|
|
217
|
+
* object that will contain all the boolean results for each group.
|
|
218
|
+
* If the iterator is infinite, the method will never return.
|
|
219
|
+
*
|
|
220
|
+
* ---
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
225
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
226
|
+
* .every(async (key, value) => value >= 0);
|
|
227
|
+
*
|
|
228
|
+
* console.log(await results.toObject()); // { odd: false, even: true }
|
|
229
|
+
* ```
|
|
230
|
+
*
|
|
231
|
+
* ---
|
|
232
|
+
*
|
|
233
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
234
|
+
*
|
|
235
|
+
* @returns
|
|
236
|
+
* A {@link Promise} resolving to a new {@link ReducedIterator} containing the boolean results for each group.
|
|
237
|
+
*/
|
|
30
238
|
public async every(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, boolean>>
|
|
31
239
|
{
|
|
32
240
|
const values = new Map<K, [number, boolean]>();
|
|
@@ -45,6 +253,38 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
45
253
|
for (const [key, [_, result]] of values) { yield [key, result]; }
|
|
46
254
|
});
|
|
47
255
|
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Determines whether any element of each group of the iterator satisfies a given condition.
|
|
259
|
+
* See also {@link AggregatedAsyncIterator.every}.
|
|
260
|
+
* This method will consume the entire iterator in the process.
|
|
261
|
+
*
|
|
262
|
+
* It will iterate over all elements of the iterator checjing if they satisfy the condition.
|
|
263
|
+
* Once a single element of one group satisfies the condition,
|
|
264
|
+
* the result for the respective group will be `true`.
|
|
265
|
+
*
|
|
266
|
+
* Eventually, it will return a new {@link ReducedIterator}
|
|
267
|
+
* object that will contain all the boolean results for each group.
|
|
268
|
+
* If the iterator is infinite, the method will never return.
|
|
269
|
+
*
|
|
270
|
+
* ---
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```ts
|
|
274
|
+
* const results = new SmartAsyncIterator<number>([-5, -4, -3, -2, -1, 0])
|
|
275
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
276
|
+
* .some(async (key, value) => value >= 0);
|
|
277
|
+
*
|
|
278
|
+
* console.log(await results.toObject()); // { odd: false, even: true }
|
|
279
|
+
* ```
|
|
280
|
+
*
|
|
281
|
+
* ---
|
|
282
|
+
*
|
|
283
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
284
|
+
*
|
|
285
|
+
* @returns
|
|
286
|
+
* A {@link Promise} resolving to a new {@link ReducedIterator} containing the boolean results for each group.
|
|
287
|
+
*/
|
|
48
288
|
public async some(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, boolean>>
|
|
49
289
|
{
|
|
50
290
|
const values = new Map<K, [number, boolean]>();
|
|
@@ -64,8 +304,69 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
64
304
|
});
|
|
65
305
|
}
|
|
66
306
|
|
|
307
|
+
/**
|
|
308
|
+
* Filters the elements of the iterator based on a given condition.
|
|
309
|
+
*
|
|
310
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
311
|
+
* If the condition is met, the element will be included in the new iterator.
|
|
312
|
+
*
|
|
313
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
314
|
+
* This means that the original iterator won't be consumed until the
|
|
315
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
316
|
+
*
|
|
317
|
+
* ---
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```ts
|
|
321
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
322
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
323
|
+
* .filter(async (key, value) => value >= 0);
|
|
324
|
+
*
|
|
325
|
+
* console.log(await results.toObject()); // { odd: [3, 5], even: [0, 2, 6, 8] }
|
|
326
|
+
* ```
|
|
327
|
+
*
|
|
328
|
+
* ---
|
|
329
|
+
*
|
|
330
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
331
|
+
*
|
|
332
|
+
* @returns A new {@link AggregatedAsyncIterator} containing the elements that satisfy the condition.
|
|
333
|
+
*/
|
|
67
334
|
public filter(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, T>;
|
|
68
|
-
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Filters the elements of the iterator based on a given condition.
|
|
338
|
+
*
|
|
339
|
+
* This method will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
340
|
+
* If the condition is met, the element will be included in the new iterator.
|
|
341
|
+
*
|
|
342
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
343
|
+
* This means that the original iterator won't be consumed until the
|
|
344
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
345
|
+
*
|
|
346
|
+
* ---
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```ts
|
|
350
|
+
* const results = new SmartAsyncIterator<number>([-3, "-1", 0, "2", "3", 5, 6, "8"])
|
|
351
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
352
|
+
* .filter<number>(async (key, value) => typeof value === "number");
|
|
353
|
+
*
|
|
354
|
+
* console.log(await results.toObject()); // { odd: [-3, 5], even: [0, 6] }
|
|
355
|
+
* ```
|
|
356
|
+
*
|
|
357
|
+
* ---
|
|
358
|
+
*
|
|
359
|
+
* @template S
|
|
360
|
+
* The type of the elements that satisfy the condition.
|
|
361
|
+
* This allows the type-system to infer the correct type of the new iterator.
|
|
362
|
+
*
|
|
363
|
+
* It must be a subtype of the original type of the elements.
|
|
364
|
+
*
|
|
365
|
+
* @param predicate The type guard condition to check for each element of the iterator.
|
|
366
|
+
*
|
|
367
|
+
* @returns A new {@link AggregatedAsyncIterator} containing the elements that satisfy the condition.
|
|
368
|
+
*/
|
|
369
|
+
public filter<S extends T>(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, S>;
|
|
69
370
|
public filter(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): AggregatedAsyncIterator<K, T>
|
|
70
371
|
{
|
|
71
372
|
const elements = this._elements;
|
|
@@ -73,17 +374,48 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
73
374
|
return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>
|
|
74
375
|
{
|
|
75
376
|
const indexes = new Map<K, number>();
|
|
76
|
-
|
|
77
377
|
for await (const [key, element] of elements)
|
|
78
378
|
{
|
|
79
379
|
const index = indexes.get(key) ?? 0;
|
|
80
|
-
|
|
81
380
|
if (await predicate(key, element, index)) { yield [key, element]; }
|
|
82
381
|
|
|
83
382
|
indexes.set(key, index + 1);
|
|
84
383
|
}
|
|
85
384
|
});
|
|
86
385
|
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Maps the elements of the iterator using a given transformation function.
|
|
389
|
+
*
|
|
390
|
+
* This method will iterate over all elements of the iterator applying the condition.
|
|
391
|
+
* The result of each transformation will be included in the new iterator.
|
|
392
|
+
*
|
|
393
|
+
* Since the iterator is lazy, the mapping process will
|
|
394
|
+
* be executed once the resulting iterator is materialized.
|
|
395
|
+
*
|
|
396
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
397
|
+
* This means that the original iterator won't be consumed until the
|
|
398
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
399
|
+
*
|
|
400
|
+
* ---
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* ```ts
|
|
404
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
405
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
406
|
+
* .map(async (key, value) => Math.abs(value));
|
|
407
|
+
*
|
|
408
|
+
* console.log(await results.toObject()); // { odd: [3, 1, 3, 5], even: [0, 2, 6, 8] }
|
|
409
|
+
* ```
|
|
410
|
+
*
|
|
411
|
+
* ---
|
|
412
|
+
*
|
|
413
|
+
* @template V The type of the elements after the transformation.
|
|
414
|
+
*
|
|
415
|
+
* @param iteratee The transformation function to apply to each element of the iterator.
|
|
416
|
+
*
|
|
417
|
+
* @returns A new {@link AggregatedAsyncIterator} containing the transformed elements.
|
|
418
|
+
*/
|
|
87
419
|
public map<V>(iteratee: MaybeAsyncKeyedIteratee<K, T, V>): AggregatedAsyncIterator<K, V>
|
|
88
420
|
{
|
|
89
421
|
const elements = this._elements;
|
|
@@ -91,22 +423,128 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
91
423
|
return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, V]>
|
|
92
424
|
{
|
|
93
425
|
const indexes = new Map<K, number>();
|
|
94
|
-
|
|
95
426
|
for await (const [key, element] of elements)
|
|
96
427
|
{
|
|
97
428
|
const index = indexes.get(key) ?? 0;
|
|
98
|
-
|
|
99
429
|
yield [key, await iteratee(key, element, index)];
|
|
100
430
|
|
|
101
431
|
indexes.set(key, index + 1);
|
|
102
432
|
}
|
|
103
433
|
});
|
|
104
434
|
}
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Reduces the elements of the iterator using a given reducer function.
|
|
438
|
+
* This method will consume the entire iterator in the process.
|
|
439
|
+
*
|
|
440
|
+
* It will iterate over all elements of the iterator applying the reducer function.
|
|
441
|
+
* The result of each iteration will be passed as the accumulator to the next one.
|
|
442
|
+
*
|
|
443
|
+
* The first accoumulator value will be the first element of the iterator.
|
|
444
|
+
* The last accumulator value will be the final result of the reduction.
|
|
445
|
+
*
|
|
446
|
+
* Eventually, it will return a new {@link ReducedIterator}
|
|
447
|
+
* object that will contain all the reduced results for each group.
|
|
448
|
+
* If the iterator is infinite, the method will never return.
|
|
449
|
+
*
|
|
450
|
+
* ---
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* ```ts
|
|
454
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
455
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
456
|
+
* .reduce(async (key, accumulator, value) => accumulator + value);
|
|
457
|
+
*
|
|
458
|
+
* console.log(await results.toObject()); // { odd: 4, even: 16 }
|
|
459
|
+
* ```
|
|
460
|
+
*
|
|
461
|
+
* ---
|
|
462
|
+
*
|
|
463
|
+
* @param reducer The reducer function to apply to each element of the iterator.
|
|
464
|
+
*
|
|
465
|
+
* @returns
|
|
466
|
+
* A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.
|
|
467
|
+
*/
|
|
105
468
|
public async reduce(reducer: MaybeAsyncKeyedReducer<K, T, T>): Promise<ReducedIterator<K, T>>;
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Reduces the elements of the iterator using a given reducer function.
|
|
472
|
+
* This method will consume the entire iterator in the process.
|
|
473
|
+
*
|
|
474
|
+
* It will iterate over all elements of the iterator applying the reducer function.
|
|
475
|
+
* The result of each iteration will be passed as the accumulator to the next one.
|
|
476
|
+
*
|
|
477
|
+
* The first accoumulator value will be the provided initial value.
|
|
478
|
+
* The last accumulator value will be the final result of the reduction.
|
|
479
|
+
*
|
|
480
|
+
* Eventually, it will return a new {@link ReducedIterator}
|
|
481
|
+
* object that will contain all the reduced results for each group.
|
|
482
|
+
* If the iterator is infinite, the method will never return.
|
|
483
|
+
*
|
|
484
|
+
* ---
|
|
485
|
+
*
|
|
486
|
+
* @example
|
|
487
|
+
* ```ts
|
|
488
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
489
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
490
|
+
* .reduce(async (key, accumulator, value) => accumulator + value, 0);
|
|
491
|
+
*
|
|
492
|
+
* console.log(await results.toObject()); // { odd: 4, even: 16 }
|
|
493
|
+
* ```
|
|
494
|
+
*
|
|
495
|
+
* ---
|
|
496
|
+
*
|
|
497
|
+
* @template A The type of the accumulator value which will also be the final result of the reduction.
|
|
498
|
+
*
|
|
499
|
+
* @param reducer The reducer function to apply to each element of the iterator.
|
|
500
|
+
* @param initialValue The initial value for the accumulator.
|
|
501
|
+
*
|
|
502
|
+
* @returns
|
|
503
|
+
* A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.
|
|
504
|
+
*/
|
|
505
|
+
public async reduce<A extends PropertyKey>(reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: MaybePromise<A>)
|
|
506
|
+
: Promise<ReducedIterator<K, A>>;
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Reduces the elements of the iterator using a given reducer function.
|
|
510
|
+
* This method will consume the entire iterator in the process.
|
|
511
|
+
*
|
|
512
|
+
* It will iterate over all elements of the iterator applying the reducer function.
|
|
513
|
+
* The result of each iteration will be passed as the accumulator to the next one.
|
|
514
|
+
*
|
|
515
|
+
* The first accoumulator value will be the provided initial value by the given function.
|
|
516
|
+
* The last accumulator value will be the final result of the reduction.
|
|
517
|
+
*
|
|
518
|
+
* Eventually, it will return a new {@link ReducedIterator}
|
|
519
|
+
* object that will contain all the reduced results for each group.
|
|
520
|
+
* If the iterator is infinite, the method will never return.
|
|
521
|
+
*
|
|
522
|
+
* ---
|
|
523
|
+
*
|
|
524
|
+
* @example
|
|
525
|
+
* ```ts
|
|
526
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
527
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
528
|
+
* .reduce(async (key, { value }, currentValue) => ({ value: value + currentValue }), (key) => ({ value: 0 }));
|
|
529
|
+
*
|
|
530
|
+
* console.log(await results.toObject()); // { odd: { value: 4 }, even: { value: 16 } }
|
|
531
|
+
* ```
|
|
532
|
+
*
|
|
533
|
+
* ---
|
|
534
|
+
*
|
|
535
|
+
* @template A The type of the accumulator value which will also be the final result of the reduction.
|
|
536
|
+
*
|
|
537
|
+
* @param reducer The reducer function to apply to each element of the iterator.
|
|
538
|
+
* @param initialValue The function that provides the initial value for the accumulator.
|
|
539
|
+
*
|
|
540
|
+
* @returns
|
|
541
|
+
* A {@link Promise} resolving to a new {@link ReducedIterator} containing the reduced results for each group.
|
|
542
|
+
*/
|
|
106
543
|
public async reduce<A>(reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue: (key: K) => MaybePromise<A>)
|
|
107
544
|
: Promise<ReducedIterator<K, A>>;
|
|
108
|
-
public async reduce<A>(
|
|
109
|
-
:
|
|
545
|
+
public async reduce<A>(
|
|
546
|
+
reducer: MaybeAsyncKeyedReducer<K, T, A>, initialValue?: MaybePromise<A> | ((key: K) => MaybePromise<A>)
|
|
547
|
+
): Promise<ReducedIterator<K, A>>
|
|
110
548
|
{
|
|
111
549
|
const values = new Map<K, [number, A]>();
|
|
112
550
|
|
|
@@ -119,7 +557,9 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
119
557
|
else if (initialValue !== undefined)
|
|
120
558
|
{
|
|
121
559
|
index = 0;
|
|
122
|
-
|
|
560
|
+
|
|
561
|
+
if (initialValue instanceof Function) { accumulator = await initialValue(key); }
|
|
562
|
+
else { accumulator = await initialValue; }
|
|
123
563
|
}
|
|
124
564
|
else
|
|
125
565
|
{
|
|
@@ -137,26 +577,94 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
137
577
|
});
|
|
138
578
|
}
|
|
139
579
|
|
|
140
|
-
|
|
580
|
+
/**
|
|
581
|
+
* Flattens the elements of the iterator using a given transformation function.
|
|
582
|
+
*
|
|
583
|
+
* This method will iterate over all elements of the iterator applying the transformation function.
|
|
584
|
+
* The result of each transformation will be included in the new iterator.
|
|
585
|
+
*
|
|
586
|
+
* Since the iterator is lazy, the mapping process will
|
|
587
|
+
* be executed once the resulting iterator is materialized.
|
|
588
|
+
*
|
|
589
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
590
|
+
* This means that the original iterator won't be consumed until the
|
|
591
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
592
|
+
*
|
|
593
|
+
* ---
|
|
594
|
+
*
|
|
595
|
+
* @example
|
|
596
|
+
* ```ts
|
|
597
|
+
* const results = new SmartAsyncIterator<number>([[-3, -1], 0, 2, 3, 5, [6, 8]])
|
|
598
|
+
* .groupBy(async (values) =>
|
|
599
|
+
* {
|
|
600
|
+
* const value = values instanceof Array ? values[0] : values;
|
|
601
|
+
* return value % 2 === 0 ? "even" : "odd";
|
|
602
|
+
* })
|
|
603
|
+
* .flatMap(async (key, values) => values);
|
|
604
|
+
*
|
|
605
|
+
* console.log(await results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }
|
|
606
|
+
* ```
|
|
607
|
+
*
|
|
608
|
+
* ---
|
|
609
|
+
*
|
|
610
|
+
* @template V The type of the elements after the transformation.
|
|
611
|
+
*
|
|
612
|
+
* @param iteratee The transformation function to apply to each element of the iterator.
|
|
613
|
+
*
|
|
614
|
+
* @returns A new {@link AggregatedAsyncIterator} containing the transformed elements.
|
|
615
|
+
*/
|
|
616
|
+
public flatMap<V>(iteratee: MaybeAsyncKeyedIteratee<K, T, V | readonly V[]>): AggregatedAsyncIterator<K, V>
|
|
141
617
|
{
|
|
142
618
|
const elements = this._elements;
|
|
143
619
|
|
|
144
620
|
return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, V]>
|
|
145
621
|
{
|
|
146
622
|
const indexes = new Map<K, number>();
|
|
147
|
-
|
|
148
623
|
for await (const [key, element] of elements)
|
|
149
624
|
{
|
|
150
625
|
const index = indexes.get(key) ?? 0;
|
|
151
626
|
const values = await iteratee(key, element, index);
|
|
152
627
|
|
|
153
|
-
|
|
628
|
+
if (values instanceof Array)
|
|
629
|
+
{
|
|
630
|
+
for (const value of values) { yield [key, value]; }
|
|
631
|
+
}
|
|
632
|
+
else { yield [key, values]; }
|
|
154
633
|
|
|
155
634
|
indexes.set(key, index + 1);
|
|
156
635
|
}
|
|
157
636
|
});
|
|
158
637
|
}
|
|
159
638
|
|
|
639
|
+
/**
|
|
640
|
+
* Drops a given number of elements from the beginning of each group of the iterator.
|
|
641
|
+
* The remaining elements will be included in the new iterator.
|
|
642
|
+
* See also {@link AggregatedAsyncIterator.take}.
|
|
643
|
+
*
|
|
644
|
+
* Since the iterator is lazy, the dropping process will
|
|
645
|
+
* be executed once the resulting iterator is materialized.
|
|
646
|
+
*
|
|
647
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
648
|
+
* This means that the original iterator won't be consumed until the
|
|
649
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
650
|
+
*
|
|
651
|
+
* ---
|
|
652
|
+
*
|
|
653
|
+
* @example
|
|
654
|
+
* ```ts
|
|
655
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
656
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
657
|
+
* .drop(2);
|
|
658
|
+
*
|
|
659
|
+
* console.log(await results.toObject()); // { odd: [3, 5], even: [6, 8] }
|
|
660
|
+
* ```
|
|
661
|
+
*
|
|
662
|
+
* ---
|
|
663
|
+
*
|
|
664
|
+
* @param count The number of elements to drop from the beginning of each group.
|
|
665
|
+
*
|
|
666
|
+
* @returns A new {@link AggregatedAsyncIterator} containing the remaining elements.
|
|
667
|
+
*/
|
|
160
668
|
public drop(count: number): AggregatedAsyncIterator<K, T>
|
|
161
669
|
{
|
|
162
670
|
const elements = this._elements;
|
|
@@ -164,7 +672,6 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
164
672
|
return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>
|
|
165
673
|
{
|
|
166
674
|
const indexes = new Map<K, number>();
|
|
167
|
-
|
|
168
675
|
for await (const [key, element] of elements)
|
|
169
676
|
{
|
|
170
677
|
const index = indexes.get(key) ?? 0;
|
|
@@ -179,6 +686,36 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
179
686
|
}
|
|
180
687
|
});
|
|
181
688
|
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Takes a given number of elements from the beginning of each group of the iterator.
|
|
692
|
+
* The elements will be included in the new iterator.
|
|
693
|
+
* See also {@link AggregatedAsyncIterator.drop}.
|
|
694
|
+
*
|
|
695
|
+
* Since the iterator is lazy, the taking process will
|
|
696
|
+
* be executed once the resulting iterator is materialized.
|
|
697
|
+
*
|
|
698
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
699
|
+
* This means that the original iterator won't be consumed until the
|
|
700
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
701
|
+
*
|
|
702
|
+
* ---
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* ```ts
|
|
706
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
707
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
708
|
+
* .take(2);
|
|
709
|
+
*
|
|
710
|
+
* console.log(await results.toObject()); // { odd: [-3, -1], even: [0, 2] }
|
|
711
|
+
* ```
|
|
712
|
+
*
|
|
713
|
+
* ---
|
|
714
|
+
*
|
|
715
|
+
* @param limit The number of elements to take from the beginning of each group.
|
|
716
|
+
*
|
|
717
|
+
* @returns A new {@link AggregatedAsyncIterator} containing the taken elements.
|
|
718
|
+
*/
|
|
182
719
|
public take(limit: number): AggregatedAsyncIterator<K, T>
|
|
183
720
|
{
|
|
184
721
|
const elements = this._elements;
|
|
@@ -186,7 +723,6 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
186
723
|
return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>
|
|
187
724
|
{
|
|
188
725
|
const indexes = new Map<K, number>();
|
|
189
|
-
|
|
190
726
|
for await (const [key, element] of elements)
|
|
191
727
|
{
|
|
192
728
|
const index = indexes.get(key) ?? 0;
|
|
@@ -199,8 +735,77 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
199
735
|
});
|
|
200
736
|
}
|
|
201
737
|
|
|
738
|
+
/**
|
|
739
|
+
* Finds the first element of each group of the iterator that satisfies a given condition.
|
|
740
|
+
* This method will consume the entire iterator in the process.
|
|
741
|
+
*
|
|
742
|
+
* It will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
743
|
+
* Once the first element of one group satisfies the condition,
|
|
744
|
+
* the result for the respective group will be the element itself.
|
|
745
|
+
*
|
|
746
|
+
* Eventually, it will return a new {@link ReducedIterator}
|
|
747
|
+
* object that will contain the first element that satisfies the condition for each group.
|
|
748
|
+
* If the iterator is infinite, the method will never return.
|
|
749
|
+
*
|
|
750
|
+
* ---
|
|
751
|
+
*
|
|
752
|
+
* @example
|
|
753
|
+
* ```ts
|
|
754
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
755
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
756
|
+
* .find(async (key, value) => value > 0);
|
|
757
|
+
*
|
|
758
|
+
* console.log(await results.toObject()); // { odd: 3, even: 2 }
|
|
759
|
+
* ```
|
|
760
|
+
*
|
|
761
|
+
* ---
|
|
762
|
+
*
|
|
763
|
+
* @param predicate The condition to check for each element of the iterator.
|
|
764
|
+
*
|
|
765
|
+
* @returns
|
|
766
|
+
* A {@link Promise} resolving to a new {@link ReducedIterator} containing
|
|
767
|
+
* the first element that satisfies the condition for each group.
|
|
768
|
+
*/
|
|
202
769
|
public async find(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, T | undefined>>;
|
|
203
|
-
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Finds the first element of each group of the iterator that satisfies a given condition.
|
|
773
|
+
* This method will consume the entire iterator in the process.
|
|
774
|
+
*
|
|
775
|
+
* It will iterate over all elements of the iterator checking if they satisfy the condition.
|
|
776
|
+
* Once the first element of one group satisfies the condition,
|
|
777
|
+
* the result for the respective group will be the element itself.
|
|
778
|
+
*
|
|
779
|
+
* Eventually, it will return a new {@link ReducedIterator}
|
|
780
|
+
* object that will contain the first element that satisfies the condition for each group.
|
|
781
|
+
* If the iterator is infinite, the method will never return.
|
|
782
|
+
*
|
|
783
|
+
* ---
|
|
784
|
+
*
|
|
785
|
+
* @example
|
|
786
|
+
* ```ts
|
|
787
|
+
* const results = new SmartAsyncIterator<number | string>([-3, "-1", 0, "2", "3", 5, 6, "8"])
|
|
788
|
+
* .groupBy(async (value) => Number(value) % 2 === 0 ? "even" : "odd")
|
|
789
|
+
* .find<number>(async (key, value) => typeof value === "number");
|
|
790
|
+
*
|
|
791
|
+
* console.log(await results.toObject()); // { odd: -3, even: 0 }
|
|
792
|
+
* ```
|
|
793
|
+
*
|
|
794
|
+
* ---
|
|
795
|
+
*
|
|
796
|
+
* @template S
|
|
797
|
+
* The type of the elements that satisfy the condition.
|
|
798
|
+
* This allows the type-system to infer the correct type of the new iterator.
|
|
799
|
+
*
|
|
800
|
+
* It must be a subtype of the original type of the elements.
|
|
801
|
+
*
|
|
802
|
+
* @param predicate The type guard condition to check for each element of the iterator.
|
|
803
|
+
*
|
|
804
|
+
* @returns
|
|
805
|
+
* A {@link Promise} resolving to a new {@link ReducedIterator} containing
|
|
806
|
+
* the first element that satisfies the condition for each group.
|
|
807
|
+
*/
|
|
808
|
+
public async find<S extends T>(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>)
|
|
204
809
|
: Promise<ReducedIterator<K, S | undefined>>;
|
|
205
810
|
|
|
206
811
|
public async find(predicate: MaybeAsyncKeyedIteratee<K, T, boolean>): Promise<ReducedIterator<K, T | undefined>>
|
|
@@ -223,6 +828,63 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
223
828
|
});
|
|
224
829
|
}
|
|
225
830
|
|
|
831
|
+
/**
|
|
832
|
+
* Enumerates the elements of the iterator.
|
|
833
|
+
* Each element is paired with its index within the group in the new iterator.
|
|
834
|
+
*
|
|
835
|
+
* Since the iterator is lazy, the enumeration process will
|
|
836
|
+
* be executed once the resulting iterator is materialized.
|
|
837
|
+
*
|
|
838
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
839
|
+
* This means that the original iterator won't be consumed until the
|
|
840
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
841
|
+
*
|
|
842
|
+
* ---
|
|
843
|
+
*
|
|
844
|
+
* @example
|
|
845
|
+
* ```ts
|
|
846
|
+
* const results = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])
|
|
847
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
848
|
+
* .enumerate();
|
|
849
|
+
*
|
|
850
|
+
* console.log(results.toObject()); // { odd: [[0, -3], [1, -1], [2, 3]], even: [[0, 0], [1, 2]] }
|
|
851
|
+
* ```
|
|
852
|
+
*
|
|
853
|
+
* ---
|
|
854
|
+
*
|
|
855
|
+
* @returns A new {@link AggregatedAsyncIterator} containing the enumerated elements.
|
|
856
|
+
*/
|
|
857
|
+
public enumerate(): AggregatedAsyncIterator<K, [number, T]>
|
|
858
|
+
{
|
|
859
|
+
return this.map((key, value, index) => [index, value]);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
/**
|
|
863
|
+
* Removes all duplicate elements from within each group of the iterator.
|
|
864
|
+
* The first occurrence of each element will be included in the new iterator.
|
|
865
|
+
*
|
|
866
|
+
* Since the iterator is lazy, the deduplication process will
|
|
867
|
+
* be executed once the resulting iterator is materialized.
|
|
868
|
+
*
|
|
869
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
870
|
+
* This means that the original iterator won't be consumed until the
|
|
871
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
872
|
+
*
|
|
873
|
+
* ---
|
|
874
|
+
*
|
|
875
|
+
* @example
|
|
876
|
+
* ```ts
|
|
877
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 6, -3, -1, 0, 5, 6, 8, 0, 2])
|
|
878
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
879
|
+
* .unique();
|
|
880
|
+
*
|
|
881
|
+
* console.log(await results.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }
|
|
882
|
+
* ```
|
|
883
|
+
*
|
|
884
|
+
* ---
|
|
885
|
+
*
|
|
886
|
+
* @returns A new {@link AggregatedAsyncIterator} containing only the unique elements.
|
|
887
|
+
*/
|
|
226
888
|
public unique(): AggregatedAsyncIterator<K, T>
|
|
227
889
|
{
|
|
228
890
|
const elements = this._elements;
|
|
@@ -230,11 +892,9 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
230
892
|
return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[K, T]>
|
|
231
893
|
{
|
|
232
894
|
const keys = new Map<K, Set<T>>();
|
|
233
|
-
|
|
234
895
|
for await (const [key, element] of elements)
|
|
235
896
|
{
|
|
236
897
|
const values = keys.get(key) ?? new Set<T>();
|
|
237
|
-
|
|
238
898
|
if (values.has(element)) { continue; }
|
|
239
899
|
|
|
240
900
|
values.add(element);
|
|
@@ -245,6 +905,28 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
245
905
|
});
|
|
246
906
|
}
|
|
247
907
|
|
|
908
|
+
/**
|
|
909
|
+
* Counts the number of elements within each group of the iterator.
|
|
910
|
+
* This method will consume the entire iterator in the process.
|
|
911
|
+
*
|
|
912
|
+
* If the iterator is infinite, the method will never return.
|
|
913
|
+
*
|
|
914
|
+
* ---
|
|
915
|
+
*
|
|
916
|
+
* @example
|
|
917
|
+
* ```ts
|
|
918
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
919
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
920
|
+
* .count();
|
|
921
|
+
*
|
|
922
|
+
* console.log(await results.toObject()); // { odd: 4, even: 4 }
|
|
923
|
+
* ```
|
|
924
|
+
*
|
|
925
|
+
* ---
|
|
926
|
+
*
|
|
927
|
+
* @returns
|
|
928
|
+
* A {@link Promise} resolving to a new {@link ReducedIterator} containing the number of elements for each group.
|
|
929
|
+
*/
|
|
248
930
|
public async count(): Promise<ReducedIterator<K, number>>
|
|
249
931
|
{
|
|
250
932
|
const counters = new Map<K, number>();
|
|
@@ -262,6 +944,32 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
262
944
|
});
|
|
263
945
|
}
|
|
264
946
|
|
|
947
|
+
/**
|
|
948
|
+
* Iterates over the elements of the iterator.
|
|
949
|
+
* The elements are passed to the given iteratee function along with their key and index within the group.
|
|
950
|
+
*
|
|
951
|
+
* This method will consume the entire iterator in the process.
|
|
952
|
+
* If the iterator is infinite, the method will never return.
|
|
953
|
+
*
|
|
954
|
+
* ---
|
|
955
|
+
*
|
|
956
|
+
* @example
|
|
957
|
+
* ```ts
|
|
958
|
+
* const aggregator = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])
|
|
959
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd");
|
|
960
|
+
*
|
|
961
|
+
* await aggregator.forEach(async (key, value, index) =>
|
|
962
|
+
* {
|
|
963
|
+
* console.log(`${index}: ${value}`); // "0: -3", "0: 0", "1: 2", "1: -1", "2: 3"
|
|
964
|
+
* };
|
|
965
|
+
* ```
|
|
966
|
+
*
|
|
967
|
+
* ---
|
|
968
|
+
*
|
|
969
|
+
* @param iteratee The function to execute for each element of the iterator.
|
|
970
|
+
*
|
|
971
|
+
* @returns A {@link Promise} that will resolve once the iteration is complete.
|
|
972
|
+
*/
|
|
265
973
|
public async forEach(iteratee: MaybeAsyncKeyedIteratee<K, T>): Promise<void>
|
|
266
974
|
{
|
|
267
975
|
const indexes = new Map<K, number>();
|
|
@@ -270,12 +978,87 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
270
978
|
{
|
|
271
979
|
const index = indexes.get(key) ?? 0;
|
|
272
980
|
|
|
273
|
-
iteratee(key, element, index);
|
|
981
|
+
await iteratee(key, element, index);
|
|
274
982
|
|
|
275
983
|
indexes.set(key, index + 1);
|
|
276
984
|
}
|
|
277
985
|
}
|
|
278
986
|
|
|
987
|
+
/**
|
|
988
|
+
* Changes the key of each element on which the iterator is aggregated.
|
|
989
|
+
* The new key is determined by the given iteratee function.
|
|
990
|
+
*
|
|
991
|
+
* Since the iterator is lazy, the reorganization process will
|
|
992
|
+
* be executed once the resulting iterator is materialized.
|
|
993
|
+
*
|
|
994
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
995
|
+
* This means that the original iterator won't be consumed until the
|
|
996
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
997
|
+
*
|
|
998
|
+
* ---
|
|
999
|
+
*
|
|
1000
|
+
* @example
|
|
1001
|
+
* ```ts
|
|
1002
|
+
* const results = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
1003
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
1004
|
+
* .map(async (key, value, index) => index % 2 === 0 ? value : -value)
|
|
1005
|
+
* .reorganizeBy(async (key, value) => value >= 0 ? "+" : "-");
|
|
1006
|
+
*
|
|
1007
|
+
* console.log(await results.toObject()); // { "+": [1, 0, 3, 6], "-": [-3, -2, -5, -8] }
|
|
1008
|
+
* ```
|
|
1009
|
+
*
|
|
1010
|
+
* ---
|
|
1011
|
+
*
|
|
1012
|
+
* @template J The type of the new key.
|
|
1013
|
+
*
|
|
1014
|
+
* @param iteratee The function to determine the new key for each element of the iterator.
|
|
1015
|
+
*
|
|
1016
|
+
* @returns A new {@link AggregatedAsyncIterator} containing the elements reorganized by the new keys.
|
|
1017
|
+
*/
|
|
1018
|
+
public reorganizeBy<J extends PropertyKey>(iteratee: MaybeAsyncKeyedIteratee<K, T, J>)
|
|
1019
|
+
: AggregatedAsyncIterator<J, T>
|
|
1020
|
+
{
|
|
1021
|
+
const elements = this._elements;
|
|
1022
|
+
|
|
1023
|
+
return new AggregatedAsyncIterator(async function* (): AsyncGenerator<[J, T]>
|
|
1024
|
+
{
|
|
1025
|
+
const indexes = new Map<K, number>();
|
|
1026
|
+
for await (const [key, element] of elements)
|
|
1027
|
+
{
|
|
1028
|
+
const index = indexes.get(key) ?? 0;
|
|
1029
|
+
yield [await iteratee(key, element, index), element];
|
|
1030
|
+
|
|
1031
|
+
indexes.set(key, index + 1);
|
|
1032
|
+
}
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* An utility method that returns a new {@link SmartAsyncIterator}
|
|
1038
|
+
* object containing all the keys of the iterator.
|
|
1039
|
+
*
|
|
1040
|
+
* Since the iterator is lazy, the keys will be extracted
|
|
1041
|
+
* be executed once the resulting iterator is materialized.
|
|
1042
|
+
*
|
|
1043
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
1044
|
+
* This means that the original iterator won't be consumed until the
|
|
1045
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
1046
|
+
*
|
|
1047
|
+
* ---
|
|
1048
|
+
*
|
|
1049
|
+
* @example
|
|
1050
|
+
* ```ts
|
|
1051
|
+
* const keys = new SmartAsyncIterator([-3, Symbol(), "A", { }, null, [1 , 2, 3], false])
|
|
1052
|
+
* .groupBy(async (value) => typeof value)
|
|
1053
|
+
* .keys();
|
|
1054
|
+
*
|
|
1055
|
+
* console.log(await keys.toArray()); // ["number", "symbol", "string", "object", "boolean"]
|
|
1056
|
+
* ```
|
|
1057
|
+
*
|
|
1058
|
+
* ---
|
|
1059
|
+
*
|
|
1060
|
+
* @returns A new {@link SmartAsyncIterator} containing all the keys of the iterator.
|
|
1061
|
+
*/
|
|
279
1062
|
public keys(): SmartAsyncIterator<K>
|
|
280
1063
|
{
|
|
281
1064
|
const elements = this._elements;
|
|
@@ -283,7 +1066,6 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
283
1066
|
return new SmartAsyncIterator<K>(async function* ()
|
|
284
1067
|
{
|
|
285
1068
|
const keys = new Set<K>();
|
|
286
|
-
|
|
287
1069
|
for await (const [key] of elements)
|
|
288
1070
|
{
|
|
289
1071
|
if (keys.has(key)) { continue; }
|
|
@@ -293,10 +1075,65 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
293
1075
|
}
|
|
294
1076
|
});
|
|
295
1077
|
}
|
|
296
|
-
|
|
1078
|
+
|
|
1079
|
+
/**
|
|
1080
|
+
* An utility method that returns a new {@link SmartAsyncIterator}
|
|
1081
|
+
* object containing all the entries of the iterator.
|
|
1082
|
+
* Each entry is a tuple containing the key and the element.
|
|
1083
|
+
*
|
|
1084
|
+
* Since the iterator is lazy, the entries will be extracted
|
|
1085
|
+
* be executed once the resulting iterator is materialized.
|
|
1086
|
+
*
|
|
1087
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
1088
|
+
* This means that the original iterator won't be consumed until the
|
|
1089
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
1090
|
+
*
|
|
1091
|
+
* ---
|
|
1092
|
+
*
|
|
1093
|
+
* @example
|
|
1094
|
+
* ```ts
|
|
1095
|
+
* const entries = new SmartAsyncIterator<number>([-3, 0, 2, -1, 3])
|
|
1096
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
1097
|
+
* .entries();
|
|
1098
|
+
*
|
|
1099
|
+
* console.log(await entries.toArray()); // [["odd", -3], ["even", 0], ["even", 2], ["odd", -1], ["odd", 3]]
|
|
1100
|
+
* ```
|
|
1101
|
+
*
|
|
1102
|
+
* ---
|
|
1103
|
+
*
|
|
1104
|
+
* @returns A new {@link SmartAsyncIterator} containing all the entries of the iterator.
|
|
1105
|
+
*/
|
|
1106
|
+
public entries(): SmartAsyncIterator<[K, T]>
|
|
297
1107
|
{
|
|
298
1108
|
return this._elements;
|
|
299
1109
|
}
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* An utility method that returns a new {@link SmartAsyncIterator}
|
|
1113
|
+
* object containing all the values of the iterator.
|
|
1114
|
+
*
|
|
1115
|
+
* Since the iterator is lazy, the values will be extracted
|
|
1116
|
+
* be executed once the resulting iterator is materialized.
|
|
1117
|
+
*
|
|
1118
|
+
* A new iterator will be created, holding the reference to the original one.
|
|
1119
|
+
* This means that the original iterator won't be consumed until the
|
|
1120
|
+
* new one is and that consuming one of them will consume the other as well.
|
|
1121
|
+
*
|
|
1122
|
+
* ---
|
|
1123
|
+
*
|
|
1124
|
+
* @example
|
|
1125
|
+
* ```ts
|
|
1126
|
+
* const values = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
1127
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd")
|
|
1128
|
+
* .values();
|
|
1129
|
+
*
|
|
1130
|
+
* console.log(await values.toArray()); // [-3, -1, 0, 2, 3, 5, 6, 8]
|
|
1131
|
+
* ```
|
|
1132
|
+
*
|
|
1133
|
+
* ---
|
|
1134
|
+
*
|
|
1135
|
+
* @returns A new {@link SmartAsyncIterator} containing all the values of the iterator.
|
|
1136
|
+
*/
|
|
300
1137
|
public values(): SmartAsyncIterator<T>
|
|
301
1138
|
{
|
|
302
1139
|
const elements = this._elements;
|
|
@@ -307,12 +1144,53 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
307
1144
|
});
|
|
308
1145
|
}
|
|
309
1146
|
|
|
1147
|
+
/**
|
|
1148
|
+
* Materializes the iterator into an array of arrays.
|
|
1149
|
+
* This method will consume the entire iterator in the process.
|
|
1150
|
+
*
|
|
1151
|
+
* If the iterator is infinite, the method will never return.
|
|
1152
|
+
*
|
|
1153
|
+
* ---
|
|
1154
|
+
*
|
|
1155
|
+
* @example
|
|
1156
|
+
* ```ts
|
|
1157
|
+
* const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
1158
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd");
|
|
1159
|
+
*
|
|
1160
|
+
* console.log(await aggregator.toArray()); // [[-3, -1, 3, 5], [0, 2, 6, 8]]
|
|
1161
|
+
* ```
|
|
1162
|
+
*
|
|
1163
|
+
* ---
|
|
1164
|
+
*
|
|
1165
|
+
* @returns A {@link Promise} resolving to an {@link Array} containing all the values of the iterator.
|
|
1166
|
+
*/
|
|
310
1167
|
public async toArray(): Promise<T[][]>
|
|
311
1168
|
{
|
|
312
1169
|
const map = await this.toMap();
|
|
313
1170
|
|
|
314
1171
|
return Array.from(map.values());
|
|
315
1172
|
}
|
|
1173
|
+
|
|
1174
|
+
/**
|
|
1175
|
+
* Materializes the iterator into a map.
|
|
1176
|
+
* This method will consume the entire iterator in the process.
|
|
1177
|
+
*
|
|
1178
|
+
* If the iterator is infinite, the method will never return.
|
|
1179
|
+
*
|
|
1180
|
+
* ---
|
|
1181
|
+
*
|
|
1182
|
+
* @example
|
|
1183
|
+
* ```ts
|
|
1184
|
+
* const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
1185
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd");
|
|
1186
|
+
*
|
|
1187
|
+
* console.log(await aggregator.toMap()); // Map(2) { "odd" => [-3, -1, 3, 5], "even" => [0, 2, 6, 8] }
|
|
1188
|
+
* ```
|
|
1189
|
+
*
|
|
1190
|
+
* ---
|
|
1191
|
+
*
|
|
1192
|
+
* @returns A {@link Promise} resolving to a {@link Map} containing all the entries of the iterator.
|
|
1193
|
+
*/
|
|
316
1194
|
public async toMap(): Promise<Map<K, T[]>>
|
|
317
1195
|
{
|
|
318
1196
|
const groups = new Map<K, T[]>();
|
|
@@ -327,6 +1205,27 @@ export default class AggregatedAsyncIterator<K extends PropertyKey, T>
|
|
|
327
1205
|
|
|
328
1206
|
return groups;
|
|
329
1207
|
}
|
|
1208
|
+
|
|
1209
|
+
/**
|
|
1210
|
+
* Materializes the iterator into an object.
|
|
1211
|
+
* This method will consume the entire iterator in the process.
|
|
1212
|
+
*
|
|
1213
|
+
* If the iterator is infinite, the method will never return.
|
|
1214
|
+
*
|
|
1215
|
+
* ---
|
|
1216
|
+
*
|
|
1217
|
+
* @example
|
|
1218
|
+
* ```ts
|
|
1219
|
+
* const aggregator = new SmartAsyncIterator<number>([-3, -1, 0, 2, 3, 5, 6, 8])
|
|
1220
|
+
* .groupBy(async (value) => value % 2 === 0 ? "even" : "odd");
|
|
1221
|
+
*
|
|
1222
|
+
* console.log(await aggregator.toObject()); // { odd: [-3, -1, 3, 5], even: [0, 2, 6, 8] }
|
|
1223
|
+
* ```
|
|
1224
|
+
*
|
|
1225
|
+
* ---
|
|
1226
|
+
*
|
|
1227
|
+
* @returns A {@link Promise} resolving to an object containing all the entries of the iterator.
|
|
1228
|
+
*/
|
|
330
1229
|
public async toObject(): Promise<Record<K, T[]>>
|
|
331
1230
|
{
|
|
332
1231
|
const groups = { } as Record<K, T[]>;
|