Created
March 28, 2019 12:32
-
-
Save leihuang23/5a8a4f18c77fabec9f89d70957f2337b to your computer and use it in GitHub Desktop.
A sequence library implemented with Crockford functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function toList(next, reversed) { | |
const arr = []; | |
let value = next(); | |
while (value !== undefined) { | |
if (reversed) { | |
arr.unshift(value); | |
value = next(); | |
} else { | |
arr.push(value); | |
value = next(); | |
} | |
} | |
return arr; | |
} | |
function getGeneratorFromList(list) { | |
let index = 0; | |
return function next() { | |
if (index < list.length) { | |
const result = list[index]; | |
index += 1; | |
return result; | |
} | |
}; | |
} | |
function createIterable(next) { | |
return { next }; | |
} | |
function createMapIterable(mapping, { next }) { | |
function map() { | |
const value = next(); | |
if (value !== undefined) { | |
return mapping(value); | |
} | |
} | |
return createIterable(map); | |
} | |
function createFilterIterable(predicate, { next }) { | |
function filter() { | |
const value = next(); | |
if (value !== undefined) { | |
if (predicate(value)) { | |
return value; | |
} | |
return filter(); | |
} | |
} | |
return createIterable(filter); | |
} | |
function createTakeIterable(limit, { next }) { | |
let count = 0; | |
function take() { | |
if (count < limit) { | |
count += 1; | |
return next(); | |
} | |
} | |
return createIterable(take); | |
} | |
function createConcatIterable({ next }, other) { | |
function concat() { | |
const value = next(); | |
return value !== undefined ? value : other.iterable.next(); | |
} | |
return createIterable(concat); | |
} | |
function createTakeWhileIterable(predicate, { next }) { | |
function takeWhile() { | |
const value = next(); | |
if (value !== undefined) { | |
if (predicate(value)) { | |
return value; | |
} | |
} | |
} | |
return createIterable(takeWhile); | |
} | |
function createSkipWhileIterable(predicate, { next }) { | |
let startTaking = false; | |
function skipWhile() { | |
const value = next(); | |
if (value !== undefined) { | |
if (startTaking) { | |
return value; | |
} else if (!predicate(value)) { | |
startTaking = true; | |
return value; | |
} | |
return skipWhile(); | |
} | |
} | |
return createIterable(skipWhile); | |
} | |
function createSkipIterable(limit, { next }) { | |
let count = 0; | |
function skip() { | |
if (count < limit) { | |
count += 1; | |
next(); | |
return skip(); | |
} | |
return next(); | |
} | |
return createIterable(skip); | |
} | |
function createDistinctIterable({ next }) { | |
const uniq = new Set(); | |
function distinct() { | |
const value = next(); | |
if (value !== undefined) { | |
if (!uniq.has(value)) { | |
uniq.add(value); | |
return value; | |
} | |
return distinct(); | |
} | |
} | |
return createIterable(distinct); | |
} | |
function createZipIterable({ next }, other) { | |
function zip() { | |
const val1 = next(); | |
const val2 = other.iterable.next(); | |
if (val1 !== undefined && val2 !== undefined) { | |
return [val1, val2]; | |
} | |
} | |
return createIterable(zip); | |
} | |
function createZipWithIterable({ next }, other, fn) { | |
function zipWith() { | |
const val1 = next(); | |
const val2 = other.iterable.next(); | |
if (val1 !== undefined && val2 !== undefined) { | |
return fn(val1, val2); | |
} | |
} | |
return createIterable(zipWith); | |
} | |
function Sequence(list) { | |
const iterable = Array.isArray(list) | |
? { next: getGeneratorFromList(list) } | |
: list; | |
let reversed; | |
function map(mapping) { | |
return Sequence(createMapIterable(mapping, iterable)); | |
} | |
function filter(predicate) { | |
return Sequence(createFilterIterable(predicate, iterable)); | |
} | |
function take(limit) { | |
return Sequence(createTakeIterable(limit, iterable)); | |
} | |
function distinct() { | |
return Sequence(createDistinctIterable(iterable)); | |
} | |
function takeWhile(predicate) { | |
return Sequence(createTakeWhileIterable(predicate, iterable)); | |
} | |
function skipWhile(predicate) { | |
return Sequence(createSkipWhileIterable(predicate, iterable)); | |
} | |
function concat(other) { | |
return Sequence(createConcatIterable(iterable, other)); | |
} | |
function reverse() { | |
reversed = !reversed; | |
return this; | |
} | |
function zip(other) { | |
return Sequence(createZipIterable(iterable, other)); | |
} | |
function zipWith(other, fn) { | |
return Sequence(createZipWithIterable(iterable, other, fn)); | |
} | |
function skip(limit) { | |
return Sequence(createSkipIterable(limit, iterable)); | |
} | |
return { | |
map, | |
filter, | |
take, | |
takeWhile, | |
skipWhile, | |
distinct, | |
reverse, | |
concat, | |
iterable, | |
zip, | |
zipWith, | |
skip, | |
toList: () => toList(iterable.next, reversed) | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment