Given the following. I want to lazily apply transform
to each member of the iterable returned from Object.keys
.
How can I do this?
function* numbers(upto, transform) {
yield* Object.keys([...Array(upto)]); // How can `transform` be applied here lazily?
}
function timesTwo(n) {
return n*2;
}
var generator = numbers(31, timesTwo)
for(var i of generator) {
console.log(i); // 0 2 4 6 8... 60
}
Since you're happy to have the transform passed into numbers
, you can apply it as you generate if you take advantage of numbers
being a generator:
function* numbers(upto, transform) {
let n = 0;
while (n < upto) {
yield transform(n);
++n;
}
}
const timesTwo = n => n * 2;
const generator = numbers(31, timesTwo);
for (const i of generator) {
console.log(i); // 0 2 4 6 8... 60
}
Live on Babel's REPL for those whose browsers won't run the above.
We could use your original definition of numbers
, but we'd either have to apply the transform eagerly instead of lazily, or we'd have to use the array's iterator (the array will be created all at once regardless). Here's that latter one:
function* numbers(upto, transform) {
for (const n of Object.keys([...Array(upto)])) {
yield transform(n);
}
}
const timesTwo = n => n * 2;
const generator = numbers(31, timesTwo);
for (const i of generator) {
console.log(i); // 0 2 4 6 8... 60
}
Live on Babel's REPL.
We could separate out the two aspects of numbers
there and have a general-purpose transform
function that is basically the generator version of map
:
function* transform(iterable, f) {
for (const v of iterable) {
yield f(v);
}
}
Then we can use that on a more basic numbers
:
function* transform(iterable, f) {
for (const v of iterable) {
yield f(v);
}
}
function* numbers(upto) {
yield* Object.keys([...Array(upto)]);
}
const timesTwo = n => n * 2;
const generator = transform(numbers(31), timesTwo);
for (const i of generator) {
console.log(i); // 0 2 4 6 8... 60
}
On Babel's REPL
Side note: I'm sure you know this, but for any lurkers, the numbers
in the question [and a couple of them below] iterates over a series of strings: "0"
, "1"
, etc. But then when we multiply with them, they get coerced to numbers. To actually have a series of numbers based on the question's numbers
approach, we'd need
yield* Object.keys([...Array(upto)]).map(Number));
function lazy(f) {
return function*(iter) {
for(const v of iter) {
yield f(v);
}
}
}
function* numbers(upto, transform) {
yield* lazy(transform)(Object.keys([...Array(upto)]));
}
function timesTwo(n) {
console.log('times two called on ', n);
return n*2;
}
var generator = numbers(11, timesTwo)
for(var i of generator) {
console.log(i); // 0 2 4 6 8... 20
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With