Ranges in Ruby
A Range object in Ruby is used to describe a set of values between a start and an end point. A basic data type in Ruby, ranges can be used to define sequences, function as conditions (Boolean flip-flops), and determine whether an interval is a member.
Creating Ranges
Usually, ranges are constructed using two or three dots between the start and finish values in a literal syntax.
Inclusive Range (..): The end value is added to the range using two dots.
Exclusive Range (…): To remove the final value from the range, use three dots.
You can also create a Range object using Range.new(begin, end, exclude_end)
. By default, exclude_end
is false
.
range_new_inclusive = Range.new(1, 3)
puts range_new_inclusive.to_a # =>
range_new_exclusive = Range.new(1, 3, true)
puts range_new_exclusive.to_a # =>
Output
1
2
3
1
2
Important Considerations
- Generally, a range cannot be considered non-empty until the end value is bigger than the beginning value. Consider (10..1).The array returned by to_a is empty [].
- They must implement the Comparable module, which means they define the <=> operator, and the objects used as range endpoints must belong to the same class or subclasses of a shared parent.
Purposes and Usage of Ranges
Ranges as Sequences: It represents an ordered succession of data and is the most natural use. You can iterate over the elements of ranges by implementing methods that they implement.
each
method: Goes over every element in the range once. Strings and integers are examples of “discrete ranges” where the endpoint class defines a succ function (for successor).step
method: As in a conventional for loop, it passes each nth element to a block as it iterates over a range.to_a
method: Transforms a range into its constituent elements in an array.
Ranges as Conditions (Boolean Flip-Flops): The.. and… operators do not produce Range objects when they are used inside a conditional expression (such as if or while). The flip-flop is a unique type of Boolean expression that they function as instead. There is an internal state (set or unset) in a flip-flop expression. Until the left-hand expression evaluates to true, it returns false; after that, it “flips” to true and stays true until the right-hand expression evaluates to true, thus it “flops” back to false.
Ranges as Intervals (Membership Testing): With ranges, you may use the ===
(case equality) operator to see if a value is within the interval they represent. In case statements, this operator is useful.
=== operator
: Tests if a value is included in the range.include?
andmember?
methods: These methods also test for membership. In Ruby 1.8,include?
andmember?
were synonyms and used a “continuous membership test” (i.e.,begin <= x <= end
orbegin <= x < end
). In Ruby 1.9, a new methodcover?
was introduced for continuous membership, whileinclude?
andmember?
use continuous testing for numeric endpoints but discrete testing for non-numeric endpoints.
Ranges for Indexing Strings and Arrays: To extract, insert, remove, or change portions of strings and arrays, use a Range object to index them.
Ranges between Dates: Date objects can also be iterated over and durations between dates represented using ranges.
Range Methods Overview
A number of practical methods are defined by the Range class:
begin
andfirst
: Return the starting object of the range.end
andlast
: Return the object that defines the end of the range.exclude_end?
: Returnstrue
if the range excludes its end value (uses three dots...
).each
: Iterates over elements.step(n)
: Iterates over everyn
th element.include?(val)
/member?(val)
: Check ifval
is a member of the range.cover?(val)
: Checks ifval
is between the start and end of the range, using a continuous membership test (Ruby 1.9+).to_a
: Converts the range to an array.
You can also read Hashes in Ruby: Understanding the Key-Value Data Structure