Edouard@3484: /* Edouard@3484: Edouard@3484: From https://github.com/keyvan-m-sadeghi/pythonic Edouard@3484: Edouard@3484: Slightly modified in order to be usable in browser (i.e. not as a node.js module) Edouard@3484: Edouard@3484: The MIT License (MIT) Edouard@3484: Edouard@3484: Copyright (c) 2016 Assister.Ai Edouard@3484: Edouard@3484: Permission is hereby granted, free of charge, to any person obtaining a copy of Edouard@3484: this software and associated documentation files (the "Software"), to deal in Edouard@3484: the Software without restriction, including without limitation the rights to Edouard@3484: use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of Edouard@3484: the Software, and to permit persons to whom the Software is furnished to do so, Edouard@3484: subject to the following conditions: Edouard@3484: Edouard@3484: The above copyright notice and this permission notice shall be included in all Edouard@3484: copies or substantial portions of the Software. Edouard@3484: Edouard@3484: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR Edouard@3484: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS Edouard@3484: FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR Edouard@3484: COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER Edouard@3484: IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN Edouard@3484: CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Edouard@3484: */ Edouard@3484: Edouard@3484: class Iterator { Edouard@3484: constructor(generator) { Edouard@3484: this[Symbol.iterator] = generator; Edouard@3484: } Edouard@3484: Edouard@3484: async * [Symbol.asyncIterator]() { Edouard@3484: for (const element of this) { Edouard@3484: yield await element; Edouard@3484: } Edouard@3484: } Edouard@3484: Edouard@3485: forEach(callback) { Edouard@3485: for (const element of this) { Edouard@3485: callback(element); Edouard@3485: } Edouard@3485: } Edouard@3485: Edouard@3484: map(callback) { Edouard@3484: const result = []; Edouard@3484: for (const element of this) { Edouard@3484: result.push(callback(element)); Edouard@3484: } Edouard@3484: Edouard@3484: return result; Edouard@3484: } Edouard@3484: Edouard@3484: filter(callback) { Edouard@3484: const result = []; Edouard@3484: for (const element of this) { Edouard@3484: if (callback(element)) { Edouard@3484: result.push(element); Edouard@3484: } Edouard@3484: } Edouard@3484: Edouard@3484: return result; Edouard@3484: } Edouard@3484: Edouard@3484: reduce(callback, initialValue) { Edouard@3484: let empty = typeof initialValue === 'undefined'; Edouard@3484: let accumulator = initialValue; Edouard@3484: let index = 0; Edouard@3484: for (const currentValue of this) { Edouard@3484: if (empty) { Edouard@3484: accumulator = currentValue; Edouard@3484: empty = false; Edouard@3484: continue; Edouard@3484: } Edouard@3484: Edouard@3484: accumulator = callback(accumulator, currentValue, index, this); Edouard@3484: index++; Edouard@3484: } Edouard@3484: Edouard@3484: if (empty) { Edouard@3484: throw new TypeError('Reduce of empty Iterator with no initial value'); Edouard@3484: } Edouard@3484: Edouard@3484: return accumulator; Edouard@3484: } Edouard@3484: Edouard@3484: some(callback) { Edouard@3484: for (const element of this) { Edouard@3484: if (callback(element)) { Edouard@3484: return true; Edouard@3484: } Edouard@3484: } Edouard@3484: Edouard@3484: return false; Edouard@3484: } Edouard@3484: Edouard@3484: every(callback) { Edouard@3484: for (const element of this) { Edouard@3484: if (!callback(element)) { Edouard@3484: return false; Edouard@3484: } Edouard@3484: } Edouard@3484: Edouard@3484: return true; Edouard@3484: } Edouard@3484: Edouard@3484: static fromIterable(iterable) { Edouard@3484: return new Iterator(function * () { Edouard@3484: for (const element of iterable) { Edouard@3484: yield element; Edouard@3484: } Edouard@3484: }); Edouard@3484: } Edouard@3484: Edouard@3484: toArray() { Edouard@3484: return Array.from(this); Edouard@3484: } Edouard@3484: Edouard@3484: next() { Edouard@3484: if (!this.currentInvokedGenerator) { Edouard@3484: this.currentInvokedGenerator = this[Symbol.iterator](); Edouard@3484: } Edouard@3484: Edouard@3484: return this.currentInvokedGenerator.next(); Edouard@3484: } Edouard@3484: Edouard@3484: reset() { Edouard@3484: delete this.currentInvokedGenerator; Edouard@3484: } Edouard@3484: } Edouard@3484: Edouard@3484: function rangeSimple(stop) { Edouard@3484: return new Iterator(function * () { Edouard@3484: for (let i = 0; i < stop; i++) { Edouard@3484: yield i; Edouard@3484: } Edouard@3484: }); Edouard@3484: } Edouard@3484: Edouard@3484: function rangeOverload(start, stop, step = 1) { Edouard@3484: return new Iterator(function * () { Edouard@3484: for (let i = start; i < stop; i += step) { Edouard@3484: yield i; Edouard@3484: } Edouard@3484: }); Edouard@3484: } Edouard@3484: Edouard@3484: function range(...args) { Edouard@3484: if (args.length < 2) { Edouard@3484: return rangeSimple(...args); Edouard@3484: } Edouard@3484: Edouard@3484: return rangeOverload(...args); Edouard@3484: } Edouard@3484: Edouard@3484: function enumerate(iterable) { Edouard@3484: return new Iterator(function * () { Edouard@3484: let index = 0; Edouard@3484: for (const element of iterable) { Edouard@3484: yield [index, element]; Edouard@3484: index++; Edouard@3484: } Edouard@3484: }); Edouard@3484: } Edouard@3484: Edouard@3484: const _zip = longest => (...iterables) => { Edouard@3594: if (iterables.length == 0) { Edouard@3594: // works starting with 1 iterable Edouard@3594: // [a,b,c] -> [[a],[b],[c]] Edouard@3594: // [a,b,c],[d,e,f] -> [[a,d],[b,e],[c,f]] Edouard@3594: throw new TypeError("zip takes 1 iterables at least, "+iterables.length+" given"); Edouard@3484: } Edouard@3484: Edouard@3484: return new Iterator(function * () { Edouard@3484: const iterators = iterables.map(iterable => Iterator.fromIterable(iterable)); Edouard@3484: while (true) { Edouard@3484: const row = iterators.map(iterator => iterator.next()); Edouard@3484: const check = longest ? row.every.bind(row) : row.some.bind(row); Edouard@3484: if (check(next => next.done)) { Edouard@3484: return; Edouard@3484: } Edouard@3484: Edouard@3484: yield row.map(next => next.value); Edouard@3484: } Edouard@3484: }); Edouard@3484: }; Edouard@3484: Edouard@3484: const zip = _zip(false), zipLongest= _zip(true); Edouard@3484: Edouard@3484: function items(obj) { Edouard@3484: let {keys, get} = obj; Edouard@3484: if (obj instanceof Map) { Edouard@3484: keys = keys.bind(obj); Edouard@3484: get = get.bind(obj); Edouard@3484: } else { Edouard@3484: keys = function () { Edouard@3484: return Object.keys(obj); Edouard@3484: }; Edouard@3484: Edouard@3484: get = function (key) { Edouard@3484: return obj[key]; Edouard@3484: }; Edouard@3484: } Edouard@3484: Edouard@3484: return new Iterator(function * () { Edouard@3484: for (const key of keys()) { Edouard@3484: yield [key, get(key)]; Edouard@3484: } Edouard@3484: }); Edouard@3484: } Edouard@3484: Edouard@3484: /* Edouard@3484: module.exports = {Iterator, range, enumerate, zip: _zip(false), zipLongest: _zip(true), items}; Edouard@3484: */