-
Notifications
You must be signed in to change notification settings - Fork 0
/
take.ts
135 lines (134 loc) · 3.67 KB
/
take.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/**
* Takes a specified number of elements from the beginning of an async iterable.
*
* ``` typescript
* import { take } from "./take.ts";
* import { count } from "./infinite.ts";
*
* const iterable = take(count(0, 5), 3);
* for await (const value of iterable) {
* console.log(value);
* }
* ```
*
* The above example will print the following 3 lines:
*
* ~~~
* 0
* 5
* 10
* ~~~
*
* If the iterable is shorter than the specified number, the whole elements are
* taken.
*
* ``` typescript
* import { take } from "./take.ts";
*
* async function* gen() { yield "foo"; yield "bar"; yield "baz"; }
* const iterable = take(gen(), 5);
* for await (const value of iterable) console.log(value);
* ```
*
* The above example will print only 3 elements, because `gen()` yields only 3
* elements:
*
* ~~~
* foo
* bar
* baz
* ~~~
*
* @template T The type of the elements in the `source` and the returned async
* iterable.
* @param source The async iterable to take elements from. It can be either
* finite or infinite.
* @param count The number of elements to take.
* @returns An async iterable that yields the first `count` elements
* from the `source` iterable.
*/
export async function* take<T>(
source: Iterable<T> | AsyncIterable<T>,
count: number,
): AsyncIterableIterator<T> {
let i = 0;
for await (const value of source) {
if (i++ >= count) break;
yield value;
}
}
/**
* Takes elements from the beginning of an async iterable as long as a specified
* condition is met. If the condition is not met, the iterable stops.
*
* ``` typescript
* import { takeWhile } from "./take.ts";
* import { count } from "./infinite.ts";
*
* const iterable = takeWhile(count(0), v => v < 4);
* for await (const value of iterable) console.log(value);
* ```
*
* The above example will print the following 4 lines:
*
* ~~~
* 0
* 1
* 2
* 3
* ~~~
*
* An async `predicate` function also works. The following example will print
* the same 4 lines as the previous example:
*
* ``` typescript
* import { takeWhile } from "./take.ts";
* import { count } from "./infinite.ts";
*
* const iterable = takeWhile(count(0), v => Promise.resolve(v < 4));
* for await (const value of iterable) console.log(value);
* ```
*
* A `predicate` function can take an index as well as the value.
*
* ``` typescript
* import { takeWhile } from "./take.ts";
* import { count } from "./infinite.ts";
*
* const iterable = takeWhile(count(0, 10), (_, i) => i < 4);
* for await (const value of iterable) console.log(value);
* ```
*
* The above example will print the following 4 lines:
*
* ~~~
* 0
* 10
* 20
* 30
* ~~~
*
* @template T The type of the elements in the `source` and the returned async
* iterable.
* @param source The async iterable to take elements from. It can be either
* finite or infinite.
* @param predicate A predicate function to test each source element for
* a condition; the second parameter of the function represents
* the index of the source element. It can be either
* synchronous or asynchronous.
* @returns An async iterable that contains elements from the `source` iterable
* that occur before the element at which the `predicate` no longer
* passes.
*/
export async function* takeWhile<T>(
source: Iterable<T> | AsyncIterable<T>,
predicate: (value: T, index: number) => boolean | Promise<boolean>,
): AsyncIterableIterator<T> {
let i = 0;
for await (const value of source) {
let cont = predicate(value, i++);
if (cont instanceof Promise) cont = await cont;
if (!cont) break;
yield value;
}
}