Is There a Reason That We Cannot Iterate on "Reverse Range" in Ruby

Is there a reason that we cannot iterate on reverse Range in ruby?

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.

Ruby : Can you please explain why reverse range not giving expected result in ruby

You asked why (5..0).to_a doesn't give the "expected result", by which I assume you mean [5,4,3,2,1].

If a range is a..b that means it includes all values x such that a <= x <= b.1 If a > b, no values are included, so nil is returned. There is no such thing as an "empty" range, as there is an empty array ([]), hash ({}), string ("") and so on. (1..1 is a range, but it is not empty.) That's why 5..3 cannot return a Range object, and therefore returns nil.

Ruby does not support the concept of a "reversed range". If you just want to step down from 3 to 1 there are many ways to do that without involving a range.

Note also that ranges, unlike arrays, for example, may contain an infinite number of values. 1.0..3.0 is one such example.

1 The range a...b (three dots) includes all values x such that a <= x < b.

Why doesn't backward for loop work in ruby? eg. for i in 10..1

1..10 is of class Range, not directly linked with any loop constructs. And there are no numbers that are both bigger than 10 and smaller than 1, therefore the range 10..1 is empty.

PS I don't recall when was the last time I wrote a for loop in ruby. Maybe something from http://www.ruby-doc.org/core-1.9.2/Enumerable.html would serve you better?

How can I iterate over a reversed range with a specific step in Ruby?

Why don't you use Numeric#step:

From the docs:

Invokes block with the sequence of numbers starting at num, incremented by step (default 1) on each call. The loop finishes when the value to be passed to the block is greater than limit (if step is positive) or less than limit (if step is negative). If all the arguments are integers, the loop operates using an integer counter. If any of the arguments are floating point numbers, all are converted to floats, and the loop is executed floor(n + n*epsilon)+ 1 times, where n = (limit - num)/step. Otherwise, the loop starts at num, uses either the < or > operator to compare the counter against limit, and increments itself using the + operator.


irb(main):001:0> 10.step(0, -2) { |i| puts i }
10
8
6
4
2
0

Why will a Range not work when descending?

The easiest way to do that is use downto

5.downto(1) do |i| puts i end

How do you reverse order in ruby

You probably want #select and #reverse.

puts (1..200).select { |i| i % 3 == 0 }.reverse

Ruby- Why can't I iterate over this data that I get back from Mongomapper map_reduce?

First you wrote @urls then @url. I think only one of them is correct.

Update: As the documentation says you can iterate over the cursor with each but after the full iteration it will be closed. Maybe this is your case that you've already iterated over it once. Probably the to_json did it.

You can check whether the cursor is closed or not with the following statement:

@urls.closed?

Check this before the iterating part.

How can I convert a step-down range to array?

1000.downto(0).each { |i| ... }        


Related Topics



Leave a reply



Submit