rubyguides

Array#rotate

rotate and rotate! shift array elements by moving the element at a given index to the front and wrapping the earlier items to the end. That makes the method useful whenever the order should advance without changing the meaning of the data.

Brief intro

rotate creates a new array with elements rearranged. rotate! modifies the original array in place. Both methods are useful for cycling through queue-like data structures or creating rotating schedules.

The method is a good fit any time the order should advance by one slot at a time. You can use it for round-robin turns, rotating menus, or any list that needs to treat the current first item as something that eventually moves to the back of the line. The behavior is simple, but it makes a lot of scheduling-style code easier to express.

The examples below move from the no-argument form to custom counts and in-place rotation. That progression is useful because the method does not change much between cases, but the effect on the source collection does, and that is the part readers usually need to keep straight.

Signature

MethodParametersReturn Type
rotatecnt = 1 (Integer)Array
rotate!cnt = 1 (Integer)Array (self)

Parameter Details:

  • cnt — The zero-based index of the element that should become the first element. Default is 1. Negative counts rotate in the opposite direction.

Code Examples

Basic Rotation

array = [1, 2, 3, 4, 5]

array.rotate
# => [2, 3, 4, 5, 1]

array
# => [1, 2, 3, 4, 5] - original unchanged

This first example shows the simplest form: the method returns a new array and leaves the original alone. That is the safest version when you want to inspect a rotated ordering without changing the source collection. The no-argument call rotates by one position, which is often the right default for round-robin patterns and simple shuffles.

Rotate with custom count

array = [1, 2, 3, 4, 5]

array.rotate(2)
# => [3, 4, 5, 1, 2]

array.rotate(0)
# => [1, 2, 3, 4, 5] - no rotation

array.rotate(5)
# => [1, 2, 3, 4, 5] - full cycle

Custom counts let you express the offset directly instead of calculating indexes by hand. A full-cycle rotation is still a useful check because it confirms that the method treats the array as circular rather than as a one-way shift.

Negative Rotation

array = [1, 2, 3, 4, 5]

array.rotate(-1)
# => [5, 1, 2, 3, 4]

array.rotate(-2)
# => [4, 5, 1, 2, 3]

Negative counts move the rotation in the opposite direction, which is handy when the item you want to expose is closer to the end than the front. The pattern is the same, but the sign of the count changes which side wraps around first. If you find yourself reaching for negative counts often, it may be worth checking whether reversing the input first keeps the logic simpler.

In-place rotation with rotate!

array = [1, 2, 3, 4, 5]

array.rotate!
# => [2, 3, 4, 5, 1]

array
# => [2, 3, 4, 5, 1] - original modified

array.rotate!(3)
# => [5, 1, 2, 3, 4]

array
# => [5, 1, 2, 3, 4]

This version is the one to use when the old ordering is no longer needed. Because the array changes in place, later code sees the new order without having to assign a separate variable. Round-robin scheduling is one of the most practical applications of this pattern, as the next example demonstrates.

Practical use: round-robin scheduling

players = ["Alice", "Bob", "Charlie", "Diana"]

# Generate schedule for 4 rounds
4.times do |round|
  puts "Round #{round + 1}: #{players.join(' vs ')}"
  players.rotate!
end

# Output:
# Round 1: Alice vs Bob vs Charlie vs Diana
# Round 2: Bob vs Charlie vs Diana vs Alice
# Round 3: Charlie vs Diana vs Alice vs Bob
# Round 4: Diana vs Alice vs Bob vs Charlie

Round-robin code is a good fit because the schedule advances by one turn at a time and the old order is not important once the next round starts. The bang variant keeps that progression compact and readable.

Return Value

  • rotate returns a new array containing the rotated elements. The original array remains unchanged.
  • rotate! returns self (the modified array), allowing method chaining.
  • When cnt equals the array length, the returned array equals the original.

That last detail is useful because it means rotation by the full length is a no-op. In practice, the method reads like a small state transition: move the front forward, keep the rest in order, and decide whether you want a copy or an in-place update.

When you are choosing between the two forms, think about whether the original ordering still matters after the rotation. If the answer is yes, use rotate; if the answer is no, rotate! keeps the code shorter.

Edge Cases

  • Empty array returns a new empty array.
  • Single-element array returns itself (new array for rotate, same for rotate!).
[].rotate
# => []

[].rotate!
# => []

[42].rotate
# => [42]

[42].rotate!
# => [42]

The edge cases stay boring in a good way, which is exactly what you want from a helper like this. Empty arrays stay empty, and single-element arrays keep the same visible order because there is nowhere meaningful to rotate.

See Also