组成发电机

时间:2016-12-28 17:13:51

标签: javascript generator

鉴于以下内容。我想懒惰地将transform应用于从Object.keys返回的可迭代的每个成员。

我该怎么做?

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
}

2 个答案:

答案 0 :(得分:5)

由于您很高兴将转换传递到numbers,因此如果您利用numbers作为生成器,则可以在生成时应用它:

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适用于那些浏览器无法运行上述内容的人。

我们可以使用numbers的原始定义,但我们要么急切地应用变换而不是懒惰,要么我们必须使用数组的迭代器(无论如何都会一次创建数组。这是后一个:

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

我们可以将numbers的两个方面分开,并且具有通用transform函数,该函数基本上是map的生成器版本:

function* transform(iterable, f) {
  for (const v of iterable) {
    yield f(v);
  }
}

然后我们可以在更基本的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

旁注:我确定知道这一点,但是对于任何潜伏者来说,问题中的numbers [及其中的几个]会迭代一系列字符串"0""1"等。但是当我们与它们相乘时,它们会被强制转换为数字。要根据问题的numbers方法实际获得一系列数字,我们需要

yield* Object.keys([...Array(upto)]).map(Number));

答案 1 :(得分:1)

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
}