JavaScript:了解生成器的使用和生成的序列

时间:2017-07-12 01:54:16

标签: javascript ecmascript-6 iterator generator

我正在尝试解决Codewars上的What's up next?挑战。挑战有一系列值作为第一个输入,序列中的项目作为第二个输入,并且需要您在紧跟指定项目后的序列中返回该项目。举个例子 -

nextItem([1, 2, 3, 4, 5, 6, 7], 3) # 4
nextItem("testing", "t") # "e"

有一个示例测试用例,它使用生成器生成值序列作为第一个参数,这就是我难倒的地方 -

function* countFrom(n) { for (let i = n; ; ++i) yield i; }
Test.assertEquals(nextItem(countFrom(1), 12), 13); 

我不确定我是否理解这台发电机是如何工作的。看一下测试用例,我最初认为生成器产生的序列为1到12,然后必须返回12之后的数字,即13.

基于此,我的代码是 -

function nextItem(xs, item) {
  // TODO: Implement me
  // if sequence is a string, like "testing"
  if (typeof xs === "string") {
    xs = arguments[0].split('');
  }

  // if sequence is an array(not a generator sequence)
  if(Array.isArray(xs)) {
     if(!xs.includes(item) || xs.lastIndexOf(item) === xs.length -1 ) {
       return undefined;
    }
  return xs[xs.indexOf(item)+1];
  }
   else {
     // if seqeunce is from a generator
     let temp = [];
     for(let i = xs.next().value; i <= arguments[1]; i++) {
       temp.push(i);
     }
    xs = temp;
     return xs[xs.length-1] + 1;
   }

}

大约一半的测试用例失败了 -

Time: 326ms Passed: 9 Failed: 9
Test Results:
Test Passed: Value == 4
Test Passed: Value == undefined
Test Passed: Value == undefined
Test Passed: Value == 'e'
Test Passed: Value == '!'
Test Passed: Value == undefined
Test Passed: Value == undefined
Test Passed: Value == 701
Expected: undefined, instead got: 661
Test Passed: Value == 661
Expected: 664, instead got: 661
Expected: undefined, instead got: 661
Expected: undefined, instead got: 661
Expected: 664, instead got: 661
Expected: 662, instead got: 661
Expected: undefined, instead got: 661
Expected: undefined, instead got: 661
Expected: 662, instead got: 661

我很确定我对如何使用这个发生器的理解是有缺陷的。在这一行 - nextItem(countFrom(1), 12)中,我不认为生成的序列是1到12.我可以告诉它生成“某些”序列,当你将12传递给函数时,它会返回下一个项目。序列 - 13.

我确实在生成器上查看了article,但不确定如何在此处应用它。

对如何解决这一挑战表示感谢。

1 个答案:

答案 0 :(得分:2)

  

我理解这台发电机是如何工作的。看一下测试用例,我最初认为生成器生成1到12的序列。

不,发生器产生无限序列。注意循环没有条件,只要你在迭代器上调用next()并向下一个yield迈出一步就会一直运行。

  

如果能解决这一挑战,我将不胜感激。

重点是字符串,数组和生成器都是iterable。你不应该区分它们并为每个案例写一个不同的案例。您应该使用通用[Symbol.iterator]()接口并通过以下方式前进:

function nextItem(xs, item) {
  const iterator = xs[Symbol.iterator]();
  var value = NaN, // bad trick: a value known not to ===item
      done = false;
  while (!done && value !== item)
    ({value, done} = iterator.next());
  return iterator.next().value;
}

或者更容易,不关心这一点,只需使用for of循环:

function nextItem(xs, item) {
  var found = false;
  for (const x of xs) {
    if (found) return x;
    found = x === item; // whether to be returned in the next iteration
  }
}