Ranges represent an interval between two values.
The most common types that support ranges are Integer
and String
.
They can be used for many things like quickly creating a collection, slicing strings, checking if a value is in a range, and iteration.
They are created using the range operator ..
or ...
(inclusive and exclusive, respectively).
1..5 # => 1..5
1...5 # => 1...5
(1..5).to_a # => [1, 2, 3, 4, 5]
(1...5).to_a # => [1, 2, 3, 4]
The reason for having two range operators is to allow to create ranges that are inclusive or exclusive of the end value, which can be useful when for example working with indexes that are zero based.
Ranges can also be created using the Range
initializer.
Range.new(1, 5) # A range containing 1, 2, 3, 4, 5
When creating a range in Ruby using the range operators ..
or ...
, and wanting to call a method on the range, you need to wrap the range in parentheses.
This is because the otherwise will the method be called on the 2nd argument of the range operator.
(1..5).sum # => 15
1..5.sum # => Error: undefined method `sum' for 5:Integer (NoMethodError)
When wanting to slice a string, you can use the range operator to get a substring. That is, by creating a range with the start and end index of the sub-string.
"Hello World"[0..4] # => "Hello"
"Hello World"[6..10] # => "World"
You can also use negative indexes to get the substring from the end of the string.
"Hello World"[-5..-1] # => "World"
"Hello World"[6..-4] # => "Wo"
Ranges do have a set of methods that can be used to work with them. For example, these methods can be used to get the sum of all the values in the range or check if the range includes a value.
Method | Description | Example |
---|---|---|
sum |
Returns the sum of all the values in the range | (1..5).sum # => 15 |
size |
Returns the size of the range | (1..5).size # => 5 |
include? |
Returns true if the range includes the given value, otherwise false
|
(1..5).include?(3) # => true |
A range can be endless and beginless.
The endless or beginless range has their start or end value being nil
, but when defining the range the nil
can be omitted.
Using beginless and endless ranges is useful when you want to, for example, slice a string from the beginning or to the end.
"Hello World"[0..] # => "Hello World"
"Hello World"[4..] # => "o World"
"Hello World"[..5] # => "Hello "
If not used on a collection, the endless range can cause an endless sequence, if not used with caution.
Strings can also be used in ranges and allow one to get an interval of strings between two strings. Its behavior can be a bit unexpected when using certain strings, so use it with caution.
"aa".."az".to_a # => ["aa", "ab", "ac", ..., "az"]
Ruby allows you to use custom objects in ranges. The requirement for this is that the object implements the following:
Comparable
modulesucc
method<=>
methodThese methods make it so that the range can iterate over the object and compare the objects in the range.
class Foo
include Comparable
attr_reader :value
def initialize(value)
@value = value
end
def succ
Foo.new(value + 1)
end
def <=>(other)
value <=> other.value
end
end
(Foo.new(1)..Foo.new(5))
# => #<Foo:0x7f3552bebe70 @value=1>, #<Foo:0x7f3552bebe50 @value=2>, #<Foo:0x7f3552bebe40 @value=3>, #<Foo:0x7f3552bebe30 @value=4>, #<Foo:0x7f3552bebe20 @value=5>