Last active
August 7, 2018 09:16
-
-
Save nodew/e0e62d8de7c083f2e5a7b5d5fb7934ff to your computer and use it in GitHub Desktop.
lazy list implementation with generators
This file contains hidden or 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 wrap(iterator) { | |
const sequence = []; | |
const next = (i) => { | |
if (sequence.length > i) { | |
return { | |
value: sequence[i], | |
done: false | |
} | |
} | |
const { value, done } = iterator.next(); | |
if (!done) { | |
sequence.push(value); | |
} | |
return { | |
value, | |
done | |
} | |
} | |
return { | |
[Symbol.iterator]: function () { | |
let i = -1; | |
return { | |
next: function () { | |
i++; | |
return next(i) | |
} | |
} | |
}, | |
next | |
} | |
} | |
const repeat = (item) => wrap(function* () { | |
while (true) { | |
yield item | |
} | |
}()) | |
const cycle = (items) => wrap(function* () { | |
const lst = Array.from(items) | |
while (true) { | |
for (let item of lst) { | |
yield item | |
} | |
} | |
}()) | |
const iterate = (fn, initial) => wrap(function* () { | |
let val = initial | |
while (true) { | |
yield val | |
val = fn(val) | |
} | |
}()) | |
const range = (start, end = Infinity, step = 1) => wrap(function* () { | |
while (start <= end) { | |
yield start | |
start += step | |
} | |
}) | |
const replicate = (item, count) => { | |
return take(repeat(item), count); | |
} | |
const map = (fn, items) => wrap(function* () { | |
for (let item of items) { | |
yield fn(item) | |
} | |
}()) | |
const filter = (predicate, items) => wrap(function *() { | |
for (let item of items) { | |
if (predicate(item)) { | |
yield item | |
} | |
} | |
}()) | |
const take = (n, items) => wrap(function* () { | |
let i = 0 | |
if (n < 1) return | |
for (let item of items) { | |
yield item | |
i++ | |
if (i >= n) { | |
return | |
} | |
} | |
}()) | |
const takeWhile = (predicate, items) => wrap(function* () { | |
for (let item of items) { | |
if (predicate(item)) { | |
yield item | |
} else { | |
return | |
} | |
} | |
}()) | |
const drop = (n, items) => wrap(function* () { | |
let i = 0 | |
for (let item of items) { | |
if (i >= n) { | |
yield item | |
} | |
i++ | |
} | |
}()) | |
const head = (items) => { | |
for (let item of items) { | |
return item; | |
} | |
} | |
const tail = (items) => wrap(function* () { | |
let visited = false; | |
for (let item of items) { | |
if (visited) { | |
yield item; | |
} else { | |
visited = true | |
} | |
} | |
}()) | |
const size = (items) => { | |
let count = 0 | |
for (let item of items) { | |
count++ | |
} | |
return count; | |
} | |
// -------------------------------- | |
const fib = (a, b) => wrap(function* () { | |
let c = 0 | |
yield a | |
yield b | |
while (true) { | |
c = a + b | |
a = b | |
b = c | |
yield c | |
} | |
}()) | |
const fibnacci = fib(1, 1); | |
console.time('first') | |
console.log(size(take(100, fibnacci))) | |
console.timeEnd('first') | |
console.time('second') | |
console.log(size(take(20, drop(10, tail(fibnacci))))) | |
console.timeEnd('second') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment