Generate Circular Array Values

Updated on 30 May, 2025
Generate Circular Array Values header image

Problem Statement

We need to work with a "circular" array where indexing beyond its bounds leads back to the start (or the end, if going in reverse). Given an initial array arr and a starting index startIndex, create a generator gen. The behavior of this generator is defined by the following steps:

  • The generator first yields the element at startIndex in arr when gen.next() is invoked without any arguments.
  • For subsequent calls to gen.next(jump), the generator calculates a new index by adding or subtracting jump to the previous index:
    • If jump is positive and stepping over the array's end, the index loops to the beginning of the array.
    • If jump is negative and stepping before the array's start, the index loops to the end of the array.
  • The generator should yield the value of arr at the new index after each call.

This task challenges our understanding of both generators in programming and manipulating indices in a cyclic manner, useful for scenarios like buffer cycling, round-robin scheduling, etc.

Examples

Example 1

Input:

arr = [1,2,3,4,5], steps = [1,2,6], startIndex = 0

Output:

[1,2,4,5]

Explanation:

 
 const gen = cycleGenerator(arr, startIndex);
 gen.next().value;  // 1, index = startIndex = 0
 gen.next(1).value; // 2, index = 1, 0 -> 1
 gen.next(2).value; // 4, index = 3, 1 -> 2 -> 3
 gen.next(6).value; // 5, index = 4, 3 -> 4 -> 0 -> 1 -> 2 -> 3 -> 4

Example 2

Input:

arr = [10,11,12,13,14,15], steps = [1,4,0,-1,-3], startIndex = 1

Output:

[11,12,10,10,15,12]

Explanation:

 const gen = cycleGenerator(arr, startIndex);
 gen.next().value;   // 11, index = 1
 gen.next(1).value; // 12, index = 2
 gen.next(4).value; // 10, index = 0
 gen.next(0).value; // 10, index = 0
 gen.next(-1).value; // 15, index = 5
 gen.next(-3).value; // 12, index = 2

Example 3

Input:

arr = [2,4,6,7,8,10], steps = [-4,5,-3,10], startIndex = 3

Output:

[7,10,8,4,10]

Explanation:

 
 const gen = cycleGenerator(arr, startIndex);
 gen.next().value   // 7, index = 3
 gen.next(-4).value // 10, index = 5
 gen.next(5).value // 8, index = 4
 gen.next(-3).value // 4, index = 1  
 gen.next(10).value // 10, index = 5

Constraints

  • 1 <= arr.length <= 104
  • 1 <= steps.length <= 100
  • -104 <= steps[i], arr[i] <= 104
  • 0 <= startIndex < arr.length

Approach and Intuition

  1. Initializing the Generator:

    • Start by creating a generator function that takes arr and startIndex.
    • Initialize the current index to startIndex and yield arr[startIndex] right away on the first .next() invocation.
  2. Handling the Jump:

    • Every subsequent .next(jump) call adjusts the current index.
    • Adjustments account for the circular nature:
      • For positive jump: (current_index + jump) % len(arr)
      • For negative jump: (current_index + jump) % len(arr) ensures the value wraps around correctly even for negative jumps (e.g., -1 from 0 goes to the last index of the array).
  3. Yielding Values:

    • Post jump adjustment, yield the value at the new index from arr.
    • The % operator is used for efficient wrap-around handling as it computes the remainder, making it apt for circular indexing—negative indices also loop back with this method correctly.

By understanding these operations, we can practically apply concepts like modulo for cyclic operations and generators for stateful iteration, which can be visualized with concrete examples. The dynamic manipulation of indices and the state retention between generator invocations makes this technique powerful for various applications in computing, such as stream processing or scheduling tasks in operating systems.

Solutions

  • JavaScript
js
var rotateElements = function* (elements, initialIndex) {
    while (true) {
        const step = yield elements.at(initialIndex % elements.length);
        initialIndex += step;
    }
}

In this solution, the task is to generate circular array values using JavaScript. The provided code employs a generator function rotateElements that iteratively yields the elements from a given array elements, starting from a specified initialIndex. The function ensures circular traversal using the modulo operator, which wraps the index around the array length.

Here's a breakdown of the process:

  • Define the generator function rotateElements with parameters elements (an array) and initialIndex (the starting index in the array).
  • Use an infinite while loop to ensure continuous iteration.
  • Use yield to return the current element of the array, wherein the index is computed as initialIndex % elements.length. This calculation helps in cycling back to the start of the array when the end is exceeded.
  • Update the initialIndex with the value step provided when the generator function is resumed. This allows the position in the array from which to yield elements to be dynamically adjusted.

This approach ensures flexibility and efficiency in working with circular arrays, especially in scenarios where the traversal order and starting position might need to be changed dynamically. The use of generator function and modulo operator here is key to achieving the desired cyclic behavior.

Comments

No comments yet.