itertools 1.7.1 → 2.0.0-beta1

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.
@@ -1,261 +0,0 @@
1
- // @flow strict
2
-
3
- import { iter, map } from './builtins';
4
- import { izip, repeat } from './itertools';
5
- import type { Predicate, Primitive } from './types';
6
- import { primitiveIdentity } from './utils';
7
-
8
- /**
9
- * Break iterable into lists of length `size`:
10
- *
11
- * [...chunked([1, 2, 3, 4, 5, 6], 3)]
12
- * // [[1, 2, 3], [4, 5, 6]]
13
- *
14
- * If the length of iterable is not evenly divisible by `size`, the last returned
15
- * list will be shorter:
16
- *
17
- * [...chunked([1, 2, 3, 4, 5, 6, 7, 8], 3)]
18
- * // [[1, 2, 3], [4, 5, 6], [7, 8]]
19
- */
20
- export function* chunked<T>(iterable: Iterable<T>, size: number): Iterable<Array<T>> {
21
- const it = iter(iterable);
22
- let r1 = it.next();
23
- if (r1.done) {
24
- return;
25
- }
26
-
27
- let chunk = [r1.value];
28
-
29
- for (const item of it) {
30
- chunk.push(item);
31
-
32
- if (chunk.length === size) {
33
- yield chunk;
34
- chunk = [];
35
- }
36
- }
37
-
38
- // Yield the remainder, if there is any
39
- if (chunk.length > 0) {
40
- yield chunk;
41
- }
42
- }
43
-
44
- /**
45
- * Return an iterator flattening one level of nesting in a list of lists:
46
- *
47
- * [...flatten([[0, 1], [2, 3]])]
48
- * // [0, 1, 2, 3]
49
- *
50
- */
51
- export function* flatten<T>(iterableOfIterables: Iterable<Iterable<T>>): Iterable<T> {
52
- for (let iterable of iterableOfIterables) {
53
- for (let item of iterable) {
54
- yield item;
55
- }
56
- }
57
- }
58
-
59
- /**
60
- * Intersperse filler element `value` among the items in `iterable`.
61
- *
62
- * >>> [...intersperse(-1, range(1, 5))]
63
- * [1, -1, 2, -1, 3, -1, 4]
64
- *
65
- */
66
- export function intersperse<T>(value: T, iterable: Iterable<T>): Iterable<T> {
67
- const stream = flatten(izip(repeat(value), iterable));
68
- take(1, stream); // eat away and discard the first value from the output
69
- return stream;
70
- }
71
-
72
- /**
73
- * Returns an iterable containing only the first `n` elements of the given
74
- * iterable.
75
- */
76
- export function* itake<T>(n: number, iterable: Iterable<T>): Iterable<T> {
77
- const it = iter(iterable);
78
- let count = n;
79
- while (count-- > 0) {
80
- let s = it.next();
81
- if (!s.done) {
82
- yield s.value;
83
- } else {
84
- // Iterable exhausted, quit early
85
- return;
86
- }
87
- }
88
- }
89
-
90
- /**
91
- * Returns an iterator of paired items, overlapping, from the original. When
92
- * the input iterable has a finite number of items `n`, the outputted iterable
93
- * will have `n - 1` items.
94
- *
95
- * >>> pairwise([8, 2, 0, 7])
96
- * [(8, 2), (2, 0), (0, 7)]
97
- *
98
- */
99
- export function* pairwise<T>(iterable: Iterable<T>): Iterable<[T, T]> {
100
- const it = iter(iterable);
101
- let r1 = it.next();
102
- if (r1.done) {
103
- return;
104
- }
105
-
106
- r1 = r1.value;
107
- for (const r2 of it) {
108
- yield [r1, r2];
109
- r1 = r2;
110
- }
111
- }
112
-
113
- /**
114
- * Returns a 2-tuple of arrays. Splits the elements in the input iterable into
115
- * either of the two arrays. Will fully exhaust the input iterable. The first
116
- * array contains all items that match the predicate, the second the rest:
117
- *
118
- * >>> const isOdd = x => x % 2 !== 0;
119
- * >>> const iterable = range(10);
120
- * >>> const [odds, evens] = partition(iterable, isOdd);
121
- * >>> odds
122
- * [1, 3, 5, 7, 9]
123
- * >>> evens
124
- * [0, 2, 4, 6, 8]
125
- *
126
- */
127
- export function partition<T>(iterable: Iterable<T>, predicate: Predicate<T>): [Array<T>, Array<T>] {
128
- let good = [];
129
- let bad = [];
130
-
131
- for (let item of iterable) {
132
- if (predicate(item)) {
133
- good.push(item);
134
- } else {
135
- bad.push(item);
136
- }
137
- }
138
-
139
- return [good, bad];
140
- }
141
-
142
- /**
143
- * Yields the next item from each iterable in turn, alternating between them.
144
- * Continues until all items are exhausted.
145
- *
146
- * >>> [...roundrobin([1, 2, 3], [4], [5, 6, 7, 8])]
147
- * [1, 4, 5, 2, 6, 3, 7, 8]
148
- */
149
- export function* roundrobin<T>(...iters: Array<Iterable<T>>): Iterable<T> {
150
- // We'll only keep lazy versions of the input iterables in here that we'll
151
- // slowly going to exhaust. Once an iterable is exhausted, it will be
152
- // removed from this list. Once the entire list is empty, this algorithm
153
- // ends.
154
- let iterables: Array<Iterator<T>> = map(iters, iter);
155
-
156
- while (iterables.length > 0) {
157
- let index = 0;
158
- while (index < iterables.length) {
159
- const it = iterables[index];
160
- const result = it.next();
161
-
162
- if (!result.done) {
163
- yield result.value;
164
- index++;
165
- } else {
166
- // This iterable is exhausted, make sure to remove it from the
167
- // list of iterables. We'll splice the array from under our
168
- // feet, and NOT advancing the index counter.
169
- iterables.splice(index, 1); // intentional side-effect!
170
- }
171
- }
172
- }
173
- }
174
-
175
- /**
176
- * Yields the heads of all of the given iterables. This is almost like
177
- * `roundrobin()`, except that the yielded outputs are grouped in to the
178
- * "rounds":
179
- *
180
- * >>> [...heads([1, 2, 3], [4], [5, 6, 7, 8])]
181
- * [[1, 4, 5], [2, 6], [3, 7], [8]]
182
- *
183
- * This is also different from `zipLongest()`, since the number of items in
184
- * each round can decrease over time, rather than being filled with a filler.
185
- */
186
- export function* heads<T>(...iters: Array<Iterable<T>>): Iterable<Array<T>> {
187
- // We'll only keep lazy versions of the input iterables in here that we'll
188
- // slowly going to exhaust. Once an iterable is exhausted, it will be
189
- // removed from this list. Once the entire list is empty, this algorithm
190
- // ends.
191
- let iterables: Array<Iterator<T>> = map(iters, iter);
192
-
193
- while (iterables.length > 0) {
194
- let index = 0;
195
- const round = [];
196
- while (index < iterables.length) {
197
- const it = iterables[index];
198
- const result = it.next();
199
-
200
- if (!result.done) {
201
- round.push(result.value);
202
- index++;
203
- } else {
204
- // This iterable is exhausted, make sure to remove it from the
205
- // list of iterables. We'll splice the array from under our
206
- // feet, and NOT advancing the index counter.
207
- iterables.splice(index, 1); // intentional side-effect!
208
- }
209
- }
210
- if (round.length > 0) {
211
- yield round;
212
- }
213
- }
214
- }
215
-
216
- /**
217
- * Non-lazy version of itake().
218
- */
219
- export function take<T>(n: number, iterable: Iterable<T>): Array<T> {
220
- return Array.from(itake(n, iterable));
221
- }
222
-
223
- /**
224
- * Yield unique elements, preserving order.
225
- *
226
- * >>> [...uniqueEverseen('AAAABBBCCDAABBB')]
227
- * ['A', 'B', 'C', 'D']
228
- * >>> [...uniqueEverseen('AbBCcAB', s => s.toLowerCase())]
229
- * ['A', 'b', 'C']
230
- *
231
- */
232
- export function* uniqueEverseen<T>(iterable: Iterable<T>, keyFn: (T) => Primitive = primitiveIdentity): Iterable<T> {
233
- let seen = new Set();
234
- for (let item of iterable) {
235
- let key = keyFn(item);
236
- if (!seen.has(key)) {
237
- seen.add(key);
238
- yield item;
239
- }
240
- }
241
- }
242
-
243
- /**
244
- * Yields elements in order, ignoring serial duplicates.
245
- *
246
- * >>> [...uniqueJustseen('AAAABBBCCDAABBB')]
247
- * ['A', 'B', 'C', 'D', 'A', 'B']
248
- * >>> [...uniqueJustseen('AbBCcAB', s => s.toLowerCase())]
249
- * ['A', 'b', 'C', 'A', 'B']
250
- *
251
- */
252
- export function* uniqueJustseen<T>(iterable: Iterable<T>, keyFn: (T) => Primitive = primitiveIdentity): Iterable<T> {
253
- let last = undefined;
254
- for (let item of iterable) {
255
- let key = keyFn(item);
256
- if (key !== last) {
257
- yield item;
258
- last = key;
259
- }
260
- }
261
- }
package/types.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export type Maybe<T> = T | undefined;
2
- export type Predicate<T> = (value: T) => boolean;
3
- export type Primitive = string | number | boolean;
package/types.js DELETED
@@ -1 +0,0 @@
1
- "use strict";
package/types.js.flow DELETED
@@ -1,5 +0,0 @@
1
- // @flow strict
2
-
3
- export type Maybe<T> = T | void;
4
- export type Predicate<T> = (T) => boolean;
5
- export type Primitive = string | number | boolean;
package/utils.d.ts DELETED
@@ -1,8 +0,0 @@
1
- import { Primitive } from './types';
2
-
3
- export type CmpFn<T> = (a: T, b: T) => number;
4
-
5
- export function keyToCmp<T>(keyFn: (value: T) => Primitive): CmpFn<T>;
6
- export function identityPredicate(x: unknown): boolean;
7
- export function numberIdentity(x: unknown): number;
8
- export function primitiveIdentity(x: unknown): Primitive;
package/utils.js DELETED
@@ -1,48 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.keyToCmp = keyToCmp;
7
- exports.identityPredicate = identityPredicate;
8
- exports.numberIdentity = numberIdentity;
9
- exports.primitiveIdentity = primitiveIdentity;
10
-
11
- function keyToCmp(keyFn) {
12
- return function (a, b) {
13
- var ka = keyFn(a);
14
- var kb = keyFn(b); // istanbul ignore else
15
-
16
- if (typeof ka === 'boolean' && typeof kb === 'boolean') {
17
- return ka === kb ? 0 : !ka && kb ? -1 : 1;
18
- } else if (typeof ka === 'number' && typeof kb === 'number') {
19
- return ka - kb;
20
- } else if (typeof ka === 'string' && typeof kb === 'string') {
21
- return ka === kb ? 0 : ka < kb ? -1 : 1;
22
- } else {
23
- return -1;
24
- }
25
- };
26
- }
27
-
28
- function identityPredicate(x) {
29
- return !!x;
30
- }
31
-
32
- function numberIdentity(x) {
33
- /* istanbul ignore if */
34
- if (typeof x !== 'number') {
35
- throw new Error('Inputs must be numbers');
36
- }
37
-
38
- return x;
39
- }
40
-
41
- function primitiveIdentity(x) {
42
- /* istanbul ignore if */
43
- if (typeof x !== 'string' && typeof x !== 'number' && typeof x !== 'boolean') {
44
- throw new Error('Please provide a key function that can establish object identity');
45
- }
46
-
47
- return x;
48
- }
package/utils.js.flow DELETED
@@ -1,42 +0,0 @@
1
- // @flow strict
2
-
3
- import type { Primitive } from './types';
4
-
5
- type CmpFn<T> = (T, T) => number;
6
-
7
- export function keyToCmp<T>(keyFn: (T) => Primitive): CmpFn<T> {
8
- return (a: T, b: T) => {
9
- let ka = keyFn(a);
10
- let kb = keyFn(b);
11
- // istanbul ignore else
12
- if (typeof ka === 'boolean' && typeof kb === 'boolean') {
13
- return ka === kb ? 0 : !ka && kb ? -1 : 1;
14
- } else if (typeof ka === 'number' && typeof kb === 'number') {
15
- return ka - kb;
16
- } else if (typeof ka === 'string' && typeof kb === 'string') {
17
- return ka === kb ? 0 : ka < kb ? -1 : 1;
18
- } else {
19
- return -1;
20
- }
21
- };
22
- }
23
-
24
- export function identityPredicate(x: mixed): boolean {
25
- return !!x;
26
- }
27
-
28
- export function numberIdentity(x: mixed): number {
29
- /* istanbul ignore if */
30
- if (typeof x !== 'number') {
31
- throw new Error('Inputs must be numbers');
32
- }
33
- return x;
34
- }
35
-
36
- export function primitiveIdentity(x: mixed): Primitive {
37
- /* istanbul ignore if */
38
- if (typeof x !== 'string' && typeof x !== 'number' && typeof x !== 'boolean') {
39
- throw new Error('Please provide a key function that can establish object identity');
40
- }
41
- return x;
42
- }