Reverse method `...` Ruby
Is there a standard method in ruby similar to (1...4).to_a
is [1,2,3,4]
, other than the reverse ie (4...1).to_a
will [4,3,2,1]
?
I understand that it is easy to define through (1...4).to_a.reverse
, but it seems strange to me that it has not yet been and 1) Am I missing something? 2) if not, is there a functional / practical reason why this has not been done yet?
source to share
(1...4)
is the range. Ranges in ruby are not like arrays; one if their advantages are that you can create a range like
(1..1e9)
without taking up all the memory of the device. Alternatively, you can create this range:
r = (1.0...4.0)
Which means "the set of all floating point numbers from 1.0 to 4.0, including 1.0, but not 4.0"
In other words:
irb(main):013:0> r.include? 3.9999
=> true
irb(main):014:0> r.include? 3.99999999999
=> true
irb(main):015:0> r.include? 4.0
=> false
you can turn an integer range into an array:
irb(main):022:0> (1..4).to_a
=> [1, 2, 3, 4]
but not a floating point range:
irb(main):023:0> (1.0...4.0).to_a
TypeError: can't iterate from Float
from (irb):23:in `each'
from (irb):23:in `to_a'
from (irb):23
from /home/mslade/rubygems1.9/bin/irb:12:in `<main>'
Because there is no natural way to iterate over floating point numbers. Instead, you use #step
:
irb(main):015:0> (1..4).step(0.5).to_a
=> [1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0]
irb(main):016:0> (1...4).step(0.5).to_a
=> [1.0, 1.5, 2.0, 2.5, 3.0, 3.5]
If you need to iterate backwards through a large integer range, use Integer#downto
.
source to share
You can fix Range # to_a to automatically work the opposite:
class Range
alias :to_a_original :to_a
def reverse
Range.new(last, first)
end
def to_a
(first < last) ? to_a_original : reverse.to_a_original.reverse
end
end
Result:
(4..1).to_a
=> [4, 3, 2, 1]
This approach is called "reopening" the aka "monkey-patching" class. Some developers like this approach because it adds useful features, some don't like it because it tinkers with the Ruby core.)
source to share