Skip to content

Maintenance Ruby 3.4 gets fixes, but no new features. Switch to Ruby 4.0 →

instance method

Range#step

(?::Numeric | ::int) -> ::Enumerator[Elem, self]
(?::Numeric | ::int) { (Elem element) -> void } -> self
(untyped) -> ::Enumerator[Elem, self]
(untyped) { (Elem element) -> void } -> self
step(s = 1) {|element| ... } → self
step(s = 1) → enumerator/arithmetic_sequence

Iterates over the elements of range in steps of s. The iteration is performed by + operator:

Example
(0..6).step(2) { puts _1 } #=> 1..5
# Prints: 0, 2, 4, 6

# Iterate between two dates in step of 1 day (24 hours)
(Time.utc(2022, 2, 24)..Time.utc(2022, 3, 1)).step(24*60*60) { puts _1 }
# Prints:
#   2022-02-24 00:00:00 UTC
#   2022-02-25 00:00:00 UTC
#   2022-02-26 00:00:00 UTC
#   2022-02-27 00:00:00 UTC
#   2022-02-28 00:00:00 UTC
#   2022-03-01 00:00:00 UTC

If + step decreases the value, iteration is still performed when step begin is higher than the end:

Example
(0..6).step(-2) { puts _1 }
# Prints nothing

(6..0).step(-2) { puts _1 }
# Prints: 6, 4, 2, 0

(Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step(-24*60*60) { puts _1 }
# Prints:
#   2022-03-01 00:00:00 UTC
#   2022-02-28 00:00:00 UTC
#   2022-02-27 00:00:00 UTC
#   2022-02-26 00:00:00 UTC
#   2022-02-25 00:00:00 UTC
#   2022-02-24 00:00:00 UTC

When the block is not provided, and range boundaries and step are Numeric, the method returns Enumerator::ArithmeticSequence.

Example
(1..5).step(2) # => ((1..5).step(2))
(1.0..).step(1.5) #=> ((1.0..).step(1.5))
(..3r).step(1/3r) #=> ((..3/1).step((1/3)))

Enumerator::ArithmeticSequence can be further used as a value object for iteration or slicing of collections (see Array#[]). There is a convenience method % with behavior similar to step to produce arithmetic sequences more expressively:

Example
# Same as (1..5).step(2)
(1..5) % 2 # => ((1..5).%(2))

In a generic case, when the block is not provided, Enumerator is returned:

Example
('a'..).step('b')         #=> #<Enumerator: "a"..:step("b")>
('a'..).step('b').take(3) #=> ["a", "ab", "abb"]

If s is not provided, it is considered 1 for ranges with numeric begin:

Example
(1..5).step { p _1 }
# Prints: 1, 2, 3, 4, 5

For non-Numeric ranges, step absence is an error:

Example
(Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step { p _1 }
# raises: step is required for non-numeric ranges (ArgumentError)

For backward compatibility reasons, String ranges support the iteration both with string step and with integer step. In the latter case, the iteration is performed by calculating the next values with String#succ:

Example
('a'..'e').step(2) { p _1 }
# Prints: a, c, e
('a'..'e').step { p _1 }
# Default step 1; prints: a, b, c, d, e

Ruby version changes

  1. 3.4
    • Range#step now consistently has a semantics of iterating by using + operator for all types, not only numerics. [Feature #18368]

      Example
      (Time.utc(2022, 2, 24)..).step(24*60*60).take(3)
      #=> [2022-02-24 00:00:00 UTC, 2022-02-25 00:00:00 UTC, 2022-02-26 00:00:00 UTC]
      
See also #size #to_a #reverse_each #to_json also in 4.1 · 4.0 · 3.3 · 3.2 · 3.1 · 3.0