I just noticed a behavior I don’t really get related to Range and
Enumerator.
if I write down something like (1…4).each { |i| p i } , this will print
1234
However, if I write (4…1).each { |i| p i }, nothing will be printed out
despite 4…1 is a valid range.
Can anyone explain me why this strange behavior is implemented as such,
and how can I circle that without the need to use the very ugly
1…4).each { |i| p (4-i) } ?
Can anyone explain me why this strange behavior is implemented as such,
and how can I circle that without the need to use the very ugly
1…4).each { |i| p (4-i) } ?
Can anyone explain me why this strange behavior is implemented as such,
and how can I circle that without the need to use the very ugly
1…4).each { |i| p (4-i) } ?
4.downto(1) { |i| p i }
This is certainly the most efficient variant. For the general case
there is Enumerable#reverse_each - at least from 1.8.7 on. Since it’s
implemented in Range as well I guess this will be efficient, too.
Thank you both, I feel ashamed that I didn’t think about “downto” …
Concerning my more general question, do you have any clue about why
decreasing ranges behave the way they do?
On Tuesday 01 February 2011 17:43:44 Stefano G. wrote:
Thank you both, I feel ashamed that I didn’t think about “downto” …
Concerning my more general question, do you have any clue about why
decreasing ranges behave the way they do?
Thank you
Range#each calls the #succ method of the starting element to get the new
one
and goes on like this until the next element is greater than the last.
If
Range#each were written in ruby, I think it could be something like this
(it’s
just a guess, I didn’t look at the actual code):
class Range
def each
current = @start
while (current <=> @end) < 1
yield current
current = current.succ
end
end
end
In your case @start would be 4, while @end would be 1. Since 4 is
greater than
1, the block is never called.
On Wednesday 02 February 2011 03:30:15 Yossef M. wrote:
Your use of <=> is perplexing, given that anything Comparable would
have a nicer operator for this purpose.
–
-yossef
Yet, it’s what Range uses. According to “The ruby programming language”,
for
an object to be used as a Range endpoint, it needs to have a <=>. It
doesn’t
need to include Comparable. Look at this:
class X
def initialize n @n = n
end
end
x1 = X.new(1)
x2 = X.new(5)
x1…x2
=> ArgumentError: bad value for range
class X
def <=> other @n <=> other.instance_variable_get(:@n)
end
end
x1…x2
=> #<X:0x8286ad8 @n=1>…#<X:0x8284ea4 @n=5>
As you see, you don’t need to have a <, > or == method, just <=>.
Stefano
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.