Implement a Stepped Iterator
BridgeSoftware Engineer · Technical ScreenLast updated
Design and implement a stepped iterator class that wraps an underlying iterator or sequence, advancing by a configurable step size on each call. This tests iterator design, state management, invariant preservation, and edge-case handling.
Problem Statement
Implement a stepped iterator class SteppedIterator that wraps an underlying iterator (or iterable sequence) and yields elements at a fixed positive step interval k.
When initialized with an underlying iterator and a positive integer step = k:
- The first call to
next()returns the first available element from the underlying iterator (index0). - Each subsequent call to
next()advances pastk - 1elements and returns thek-th element (indicesk,2k,3k, ...). - Calling
hasNext()returnsTrueif there is at least one more stepped element available to consume, andFalseotherwise. CallinghasNext()multiple times consecutively without callingnext()must be idempotent and must not alter the iteration state. - If
next()is called when no elements remain, it should raise aStopIterationexception.
Your implementation should work with any standard iterator (which may only support single forward passes without random access or length introspection) using O(1) auxiliary space beyond buffering the next stepped item.
Class Interface
from typing import Any, Iterator
class SteppedIterator:
def __init__(self, iterator: Iterator[Any], step: int):
"""
Initializes the stepped iterator.
:param iterator: The underlying iterator to wrap.
:param step: A positive integer indicating step size (k >= 1).
"""
pass
def hasNext(self) -> bool:
"""
Returns True if the iteration has more elements.
"""
pass
def next(self) -> Any:
"""
Returns the next element in the stepped iteration.
Raises StopIteration if no further elements exist.
"""
pass
Constraints
1 <= step <= 10^9- The underlying iterator may be infinite, empty, or contain up to
10^6elements. - Time complexity per call to
next()should beO(step)operations on the underlying iterator. - Space complexity must be
O(1)auxiliary memory.
Examples
Example 1
source = iter([10, 20, 30, 40, 50, 60, 70])
it = SteppedIterator(source, step=2)
assert it.hasNext() == True
assert it.next() == 10 # index 0
assert it.hasNext() == True
assert it.next() == 30 # index 2
assert it.next() == 50 # index 4
assert it.next() == 70 # index 6
assert it.hasNext() == False
# Calling it.next() now raises StopIteration
Example 2
source = iter([1, 2, 3, 4, 5])
it = SteppedIterator(source, step=3)
assert it.next() == 1 # index 0
assert it.next() == 4 # index 3
assert it.hasNext() == False
Edge Cases to Consider
step == 1: Acts identically to the underlying iterator.- Empty underlying iterator:
hasNext()returnsFalseimmediately, andnext()raisesStopIteration. - Fewer elements remaining than
step: Ensure remaining elements are exhausted cleanly without indexing errors. - Multiple consecutive calls to
hasNext()before callingnext().
Hints
Hint 1
Because the underlying iterator can only be read forward once, maintain a single lookahead buffer storing the next element to return.
Hint 2
Use a flag or sentinel to track whether the lookahead buffer currently contains a valid element, and load the next valid element lazily when needed.
Hint 3
When advancing to the next target element, consume and discard exactly `step - 1` elements from the underlying iterator before capturing the next value.
Follow-up questions
- How would you support a dynamic `setStep(new_step)` method that changes the step size on the fly between `next()` calls?
- If the underlying sequence supports random access `__getitem__` (like an array or list), how would you optimize `next()` from `O(step)` to `O(1)`?
- How would you ensure thread-safety if multiple threads might concurrently call `hasNext()` and `next()`?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.