Enumerable#cycle

Updated March 31, 2026 · Enumerable
ruby enumerable cycle loop stdlib

#cycle repeats the elements of an array (or any enumerable) indefinitely, or for a specific number of times. It is useful for round-robin scheduling, rotating through options, and generating repeating patterns without writing manual loops.

Basic Usage

When called with a block, #cycle yields each element in order, then starts over from the beginning:

[:gold, :silver, :bronze].cycle { |medal| puts medal }
# gold
# silver
# bronze
# gold
# silver
# bronze
# ... forever until interrupted

This will run forever unless you explicitly break out of it.

Cycling a Specific Number of Times

Pass an integer to #cycle(n) to repeat the collection exactly n times:

[:left, :right].cycle(3) { |direction| puts direction }
# left
# right
# left
# right
# left
# right

After completing the specified number of cycles, the loop ends and #cycle returns nil.

Breaking Out of a Cycle

Use break to stop early, just like any other loop:

result = []
[1, 2, 3].cycle.take(5) { |n| result << n }
result
# => [1, 2, 3, 1, 2]

The #take method here limits the iteration to 5 elements before the cycle is exhausted.

Without a Block — Returns an Enumerator

Called without a block, #cycle returns an Enumerator so you can chain other Enumerable methods:

enum = [1, 2, 3].cycle
enum.take(5)
# => [1, 2, 3, 1, 2]

enum = [:a, :b, :c].cycle(2)
enum.to_a
# => [:a, :b, :c, :a, :b, :c]

Practical Examples

Round-Robin Scheduling

Assign tasks to workers in rotation:

workers = [:alice, :bob, :carol]
tasks   = [:upload, :process, :deliver, :archive, :notify]

assignments = tasks.zip(workers.cycle)
assignments
# => [[:upload, :alice], [:process, :bob], [:deliver, :carol],
#      [:archive, :alice], [:notify, :bob]]

Rotating Menus

Display items in a repeating carousel:

menu = ["Breakfast", "Lunch", "Dinner"]
menu.cycle.take(7)
# => ["Breakfast", "Lunch", "Dinner", "Breakfast", "Lunch", "Dinner", "Breakfast"]

Generating a Repeating Pattern

# Create 12 months organized by quarter
quarters = ["Q1", "Q2", "Q3", "Q4"]
quarters.cycle.take(12)
# => ["Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4", "Q1", "Q2", "Q3", "Q4"]

Using cycle with break

result = []
[10, 20, 30].cycle do |n|
  break if n == 30
  result << n
end
result
# => [10, 20]

Performance Notes

  • cycle creates an Enumerator lazily. No array duplication occurs until you consume it.
  • Calling cycle with no argument on a large or infinite collection without break or take will consume all available memory eventually.
  • For a known number of iterations, always pass that count: cycle(n) instead of cycle { ... } with a manual counter. It avoids the overhead of checking a break condition on every iteration.
  • Chaining #cycle with #first(n) or #take(n) is more idiomatic and safer than relying on break inside the block.

Return Value

FormReturn Value
`collection.cycle {x
`collection.cycle(n) {x
collection.cycle (no block)Enumerator
collection.cycle(n) (no block)Enumerator

See Also