I’m a bit confused by some Ruby behavior I’m seeing with ranges. As I
understand it the difference between
0…5
and
0…5
is that the former includes the number 5 while the 2nd does not. That
seems to be the case, but one would expect the same type of behavior
in boolean context. For example, I’d think
0.upto(9) do |x|
if (x==3)…(x==5)
puts "In the range: #{x}"
else
puts "Not in the range: #{x}"
end
end
Would output:
Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
In the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9
while using the 3 dot form like this:
0.upto(9) do |x|
if (x==3)…(x==5)
puts "In the range: #{x}"
else
puts "Not in the range: #{x}"
end
end
Would output:
Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
Not in the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9
However, the 3 dot form doesn’t work as expected. It outputs the same
as the 2 dot form (which works as expected). What gives? This seems
unintuitive to me. Any thoughts?
I’m a bit confused by some Ruby behavior I’m seeing with ranges. As I
understand it the difference between
0…5
and
0…5
is that the former includes the number 5 while the 2nd does not. That
seems to be the case, but one would expect the same type of behavior
in boolean context. For example, I’d think
0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end
Would output:
Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
In the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9
while using the 3 dot form like this:
0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end
Would output:
Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
Not in the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9
However, the 3 dot form doesn’t work as expected. It outputs the same
as the 2 dot form (which works as expected). What gives? This seems
unintuitive to me. Any thoughts?
I’m a bit confused by some Ruby behavior I’m seeing with ranges. As I
understand it the difference between
0…5
and
0…5
is that the former includes the number 5 while the 2nd does not. That
seems to be the case, but one would expect the same type of behavior
in boolean context. For example, I’d think
0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end
Would output:
Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
In the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9
while using the 3 dot form like this:
0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end
Would output:
Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
Not in the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9
However, the 3 dot form doesn’t work as expected. It outputs the same
as the 2 dot form (which works as expected). What gives? This seems
unintuitive to me. Any thoughts?
Thanks,
Oliver
change: if (x==3)…(x==5) and (x==3)…(x==5)
to: if (3…5).include?(x) or (3…5).include?(x)
or: if (3…5).include? x or (3…5).include? x
for second case, you get output: “Not in the range: 5”
When operator ‘…’ or ‘…’ is used in the condition expression,
it works like a flip-flop switch and returns true/false
(default is false).
The difference of the two is the timing of evaluation.
I think it is Perl-like.
a=[1,2,‘a’,3,4,5,6,‘b’,7,8,9]
a.each do |x|
if (x == ‘a’)…(x.is_a? String)
print x
end
end
#=> a
a.each do |x|
if (x == ‘a’)…(x.is_a? String)
print x
end
end
#=> a3456b
I’m a bit confused by some Ruby behavior I’m seeing with ranges. As I
understand it the difference between
0…5
and
0…5
is that the former includes the number 5 while the 2nd does not. That
seems to be the case, but one would expect the same type of behavior
in boolean context. For example, I’d think
0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end
Would output:
Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
In the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9
while using the 3 dot form like this:
0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end
Would output:
Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
Not in the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9
However, the 3 dot form doesn’t work as expected. It outputs the same
as the 2 dot form (which works as expected). What gives? This seems
unintuitive to me. Any thoughts?
That’ll probably work… but I’m curious to know if Oliver Dain’s method
is supposed to work:
if (x==3)…(x==5)
and
if (x==3)…(x==5)
I’m surprised that they work at all, and I’m curious if the fact they
work in some way is a fluke, or if it was a conscious decision to try to
let them work like that. I’d expect a syntax error, but then again,
ranges as objects confuse me.
0.upto(9) do |x|
if (x==3)…(x==5)
puts “In the range: #{x}”
else
puts “Not in the range: #{x}”
end
end
Would output:
Not in the range: 0
Not in the range: 1
Not in the range: 2
In the range: 3
In the range: 4
In the range: 5
Not in the range: 6
Not in the range: 7
Not in the range: 8
Not in the range: 9
[snip]
···
change: if (x==3)…(x==5) and (x==3)…(x==5)
to: if (3…5).include?(x) or (3…5).include?(x)
or: if (3…5).include? x or (3…5).include? x
for second case, you get output: “Not in the range: 5”
That’ll probably work… but I’m curious to know if Oliver Dain’s
method
is supposed to work:
if (x==3)…(x==5)
and
if (x==3)…(x==5)
I’m surprised that they work at all, and I’m curious if the fact
they work in some way is a fluke, or if it was a conscious decision
to try to
let them work like that. I’d expect a syntax error, but then again,
ranges as objects confuse me.
Ben
Its my understanding that its not a fluke but a design decision. The
main reason for doing it, I think, is for regex’s. It allows you to
say things like:
while gets
print if /foo/…/bar/
end
e.g. print all lines between foo and bar. While Sean’s solution works
for numbers it doesn’t work for regular expressions and that was my
application of interest (I gave a numerical example because it was
easier to understand).
Yes, but this is a single boolean not a boolean range. From what I
understand of the flipflop behaviour, the two dot case behaves like
this:
flag = true if (x==3)
if flag
body
end
flag = false if (x==5)
so by analogy, I’d expect the three dot case to be
flag = true if (x==3)
flag = false if (x==5)
if flag
body
end
martin
I think you’ve got the 2 dot case right, but the 3 dot case is wrong.
Just to make the 2-dot and 3-dot cases look similar, here’s another
way to write the 2 dot code:
if flag == true
body
if (x==5) flag = false
else
if (x==3) flag = true
body
if (x==5) flag = false
end
Then the 3 dot case the code is:
if flag == true
body
if (x==5) flag = false
else
if (x==3) flag = true
body
end
The only difference is that if the an x matches both the beginning and
end condition your code doesn’t execute body for that x while mine
does:
For example:
0.upto(9) {|x|
if (x==3)…(x==3)
puts “#{x} is a match”
end
}
produces:
3 is a match
4 is a match
5 is a match
6 is a match
7 is a match
8 is a match
9 is a match
your pseudo-code wouldn’t have produced any output as x would have set
the flag true, but then immediately set it false and body would never
execute. What acutally happens is that when x is 3 it sets flag to
true. The end condition is not checked that iteration in the 3 dot
case. On the rest of the iterations the end condition is checked
but it is never true so all the rest of the values are output.
Just for reference, here’s what the 2 dot case does:
0.upto(9) {|x|
if (x==3)…(x==3)
puts “#{x} is a match”
end
}
The above code is, I think, interpreted completely differently that
the “if (3==3)…(3==3)” code. Why? The latter is a boolean range
while the former first creates a range object and then applied
operator === to that. Things like ‘print if /foo/…/bar/’ operate
differently than other types of ranges because they’re boolean
ranges. For example you might think
ruby -ne ‘print if /foo/…/bar/’
would print all lines starting with the one that matches /foo/ up to,
but not including (since its a 3 dot range) the line that matches
/bar/. That would match the meaning of a “regular” range. But
that’s not how it works. Instead the above will match all lines
between /foo/ and /bar/ including the /bar/ line.
I think this is a really confusing distinction and I would prefer if
the boolean context range acted the same way as a regular range (e.g.
the 3 dot form means the end point isn’t included in the range,
etc.), but that isn’t how its done.
The above code is, I think, interpreted completely differently that
the “if (3==3)…(3==3)” code. Why? The latter is a boolean range
while the former first creates a range object and then applied
operator === to that. Things like ‘print if /foo/…/bar/’ operate
differently than other types of ranges because they’re boolean
ranges. For example you might think