Skip to content

Instantly share code, notes, and snippets.

@leihuang23
Created March 28, 2019 12:32
Show Gist options
  • Save leihuang23/5a8a4f18c77fabec9f89d70957f2337b to your computer and use it in GitHub Desktop.
Save leihuang23/5a8a4f18c77fabec9f89d70957f2337b to your computer and use it in GitHub Desktop.
A sequence library implemented with Crockford functions
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