1

I'm trying to solve the What's up next? challenge on Codewars. The challenge has a sequence of values as the first input, an item in the sequence as the second input, and needs you to return the item in the sequence immediately following the specified item. Given examples -

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

There is a sample test case which uses a generator to produce the sequence of values as the first argument, and this is where I'm stumped -

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

I'm not sure if I understand how this generator works. Looking at the test case, I initially thought the generator produces a sequence of 1 through 12, and then the number just after 12 has to be returned ie 13.

Based on that, my code was -

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;
   }

}

This fails about half the test cases -

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

I'm pretty sure my understanding of how the generator here is used is flawed. In this line - nextItem(countFrom(1), 12), I don't think the generated sequence is 1 through 12. What I can tell is it generates "some" sequence and when you pass 12 to the function, it returns the next item in the sequence - 13.

I did go through this article on generators, but not sure how to apply it here.

Would appreciate any explanation as to how to solve this challenge.

1 Answer 1

3

I understand how this generator works. Looking at the test case, I initially thought the generator produces a sequence of 1 through 12.

No, the generator produces an infinite sequence. Notice the loop has no condition, it runs forever as long you call next() on the iterator and make a step to the next yield.

I would appreciate any explanation as to how to solve this challenge.

The main point is that strings, arrays and generators are all iterable. You are not supposed to distinguish them and write a different case for each. You just should use the generic [Symbol.iterator]() interface and advance through that:

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;
}

Or even easier, don't care about that and just use a for of loop:

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
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

In the first example, the while could also be swapped for (const value of iterator) if (value === item) break; since iterators are also iterable.
@loganfsmyth Nice, didn't think of that, it would allow us to avoid the found flag in the second example. In the first snippet, I wanted to explicitly use .next() however
@Bergi Thanks a bunch! Learnt a new thing today, very useful.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.