|
1 /* |
|
2 |
|
3 From https://github.com/keyvan-m-sadeghi/pythonic |
|
4 |
|
5 Slightly modified in order to be usable in browser (i.e. not as a node.js module) |
|
6 |
|
7 The MIT License (MIT) |
|
8 |
|
9 Copyright (c) 2016 Assister.Ai |
|
10 |
|
11 Permission is hereby granted, free of charge, to any person obtaining a copy of |
|
12 this software and associated documentation files (the "Software"), to deal in |
|
13 the Software without restriction, including without limitation the rights to |
|
14 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of |
|
15 the Software, and to permit persons to whom the Software is furnished to do so, |
|
16 subject to the following conditions: |
|
17 |
|
18 The above copyright notice and this permission notice shall be included in all |
|
19 copies or substantial portions of the Software. |
|
20 |
|
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS |
|
23 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR |
|
24 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
|
25 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
|
26 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
27 */ |
|
28 |
|
29 class Iterator { |
|
30 constructor(generator) { |
|
31 this[Symbol.iterator] = generator; |
|
32 } |
|
33 |
|
34 async * [Symbol.asyncIterator]() { |
|
35 for (const element of this) { |
|
36 yield await element; |
|
37 } |
|
38 } |
|
39 |
|
40 forEach(callback) { |
|
41 for (const element of this) { |
|
42 callback(element); |
|
43 } |
|
44 } |
|
45 |
|
46 map(callback) { |
|
47 const result = []; |
|
48 for (const element of this) { |
|
49 result.push(callback(element)); |
|
50 } |
|
51 |
|
52 return result; |
|
53 } |
|
54 |
|
55 filter(callback) { |
|
56 const result = []; |
|
57 for (const element of this) { |
|
58 if (callback(element)) { |
|
59 result.push(element); |
|
60 } |
|
61 } |
|
62 |
|
63 return result; |
|
64 } |
|
65 |
|
66 reduce(callback, initialValue) { |
|
67 let empty = typeof initialValue === 'undefined'; |
|
68 let accumulator = initialValue; |
|
69 let index = 0; |
|
70 for (const currentValue of this) { |
|
71 if (empty) { |
|
72 accumulator = currentValue; |
|
73 empty = false; |
|
74 continue; |
|
75 } |
|
76 |
|
77 accumulator = callback(accumulator, currentValue, index, this); |
|
78 index++; |
|
79 } |
|
80 |
|
81 if (empty) { |
|
82 throw new TypeError('Reduce of empty Iterator with no initial value'); |
|
83 } |
|
84 |
|
85 return accumulator; |
|
86 } |
|
87 |
|
88 some(callback) { |
|
89 for (const element of this) { |
|
90 if (callback(element)) { |
|
91 return true; |
|
92 } |
|
93 } |
|
94 |
|
95 return false; |
|
96 } |
|
97 |
|
98 every(callback) { |
|
99 for (const element of this) { |
|
100 if (!callback(element)) { |
|
101 return false; |
|
102 } |
|
103 } |
|
104 |
|
105 return true; |
|
106 } |
|
107 |
|
108 static fromIterable(iterable) { |
|
109 return new Iterator(function * () { |
|
110 for (const element of iterable) { |
|
111 yield element; |
|
112 } |
|
113 }); |
|
114 } |
|
115 |
|
116 toArray() { |
|
117 return Array.from(this); |
|
118 } |
|
119 |
|
120 next() { |
|
121 if (!this.currentInvokedGenerator) { |
|
122 this.currentInvokedGenerator = this[Symbol.iterator](); |
|
123 } |
|
124 |
|
125 return this.currentInvokedGenerator.next(); |
|
126 } |
|
127 |
|
128 reset() { |
|
129 delete this.currentInvokedGenerator; |
|
130 } |
|
131 } |
|
132 |
|
133 function rangeSimple(stop) { |
|
134 return new Iterator(function * () { |
|
135 for (let i = 0; i < stop; i++) { |
|
136 yield i; |
|
137 } |
|
138 }); |
|
139 } |
|
140 |
|
141 function rangeOverload(start, stop, step = 1) { |
|
142 return new Iterator(function * () { |
|
143 for (let i = start; i < stop; i += step) { |
|
144 yield i; |
|
145 } |
|
146 }); |
|
147 } |
|
148 |
|
149 function range(...args) { |
|
150 if (args.length < 2) { |
|
151 return rangeSimple(...args); |
|
152 } |
|
153 |
|
154 return rangeOverload(...args); |
|
155 } |
|
156 |
|
157 function enumerate(iterable) { |
|
158 return new Iterator(function * () { |
|
159 let index = 0; |
|
160 for (const element of iterable) { |
|
161 yield [index, element]; |
|
162 index++; |
|
163 } |
|
164 }); |
|
165 } |
|
166 |
|
167 const _zip = longest => (...iterables) => { |
|
168 if (iterables.length < 2) { |
|
169 throw new TypeError("zip takes 2 iterables at least, "+iterables.length+" given"); |
|
170 } |
|
171 |
|
172 return new Iterator(function * () { |
|
173 const iterators = iterables.map(iterable => Iterator.fromIterable(iterable)); |
|
174 while (true) { |
|
175 const row = iterators.map(iterator => iterator.next()); |
|
176 const check = longest ? row.every.bind(row) : row.some.bind(row); |
|
177 if (check(next => next.done)) { |
|
178 return; |
|
179 } |
|
180 |
|
181 yield row.map(next => next.value); |
|
182 } |
|
183 }); |
|
184 }; |
|
185 |
|
186 const zip = _zip(false), zipLongest= _zip(true); |
|
187 |
|
188 function items(obj) { |
|
189 let {keys, get} = obj; |
|
190 if (obj instanceof Map) { |
|
191 keys = keys.bind(obj); |
|
192 get = get.bind(obj); |
|
193 } else { |
|
194 keys = function () { |
|
195 return Object.keys(obj); |
|
196 }; |
|
197 |
|
198 get = function (key) { |
|
199 return obj[key]; |
|
200 }; |
|
201 } |
|
202 |
|
203 return new Iterator(function * () { |
|
204 for (const key of keys()) { |
|
205 yield [key, get(key)]; |
|
206 } |
|
207 }); |
|
208 } |
|
209 |
|
210 /* |
|
211 module.exports = {Iterator, range, enumerate, zip: _zip(false), zipLongest: _zip(true), items}; |
|
212 */ |