Is there a reason that we cannot iterate on "reverse Range" in ruby?
I tried to iterate backwards with using a Range and each
:
(4..0).each do |i|
puts i
end
==> 4..0
Iteration through 0..4
writes the numbers. On the other Range r = 4..0
seems to be ok, r.first == 4
, r.last == 0
.
It seems to be strange to me that the construct above does not produce the expected result. What is the a reason for that? What are the situations when this behaviour is reasonable?
A range is just that: something defined by its start and end, not by its contents. "Iterating" over a range doesn't really make sense in a general case. Consider, for example, how you would "iterate" over the range produced by two dates. Would you iterate by day? by month? by year? by week? It's not well-defined. IMO, the fact that it's allowed for forward ranges should be viewed as a convenience method only.
If you want to iterate backwards over a range like that, you can always use downto
:
$ r = 10..6
=> 10..6
$ (r.first).downto(r.last).each { |i| puts i }
10
9
8
7
6
Here are some more thoughts from others on why it's tough to both allow iteration and consistently deal with reverse-ranges.
How about (0..1).reverse_each
which iterates the range backwards?
Iterating over a range in Ruby with each
calls the succ
method on the first object in the range.
$ 4.succ
=> 5
And 5 is outside the range.
You can simulate reverse iteration with this hack:
(-4..0).each { |n| puts n.abs }
John pointed out that this will not work if it spans 0. This would:
>> (-2..2).each { |n| puts -n }
2
1
0
-1
-2
=> -2..2
Can't say I really like any of them because they kind of obscure the intent.
Another way is (1..10).to_a.reverse