Intervals in Ruby

Howdy,

I'm not a Ruby developer *at all*, I use Python, but this is not flame-
bait. I'm interested in how Ruby folks find using intervals.

In Python, we deal with integer ranges virtually exclusively with the
range() function. range() always results in a half-open interval:

range(5) => 0, 1, 2, 3, 4
range(1, 5) => 1, 2, 3, 4
range(4, -1, -1) => 4, 3, 2, 1, 0

The start argument is always included, the end argument is never
included, and there is an optional step size (defaults to 1).

I understand that in Ruby you have quite a few choices, some of which are
half-open like Python, some of which are closed:

0..5 => 0, 1, 2, 3, 4, 5
0...5 => 0, 1, 2, 3, 4

5.downto(1) => 5, 4, 3, 2, 1
1.upto(5) => 1, 2, 3, 4, 5
5.times() => 0, 1, 2, 3, 4
5.step(11, 3) => 5, 8, 11

and the Range.new method.

My question is: how useful are all these different mechanisms? Do you
find that having two operators .. and ... is a blessing, or a curse
because you can never remember which is which?

How useful are the closed interval forms? Do you find yourself making off-
by-one errors or needing to increment/decrement variables by one?

e.g. do you often need to write things like:

start.step(end + 1, increment){| i | block }
start.step(end - 1, increment){| i | block }

Writing in Python, I almost never need to "shift the fence-posts", so to
speak. E.g. I virtually never need to write something like:

range(start, end+1)

to avoid an off-by-one error. When I used to program in Pascal (which
exclusively uses closed intervals) I used to need to do it all the time.
What's the Ruby experience?

Thank you,

···

--
Steven

Hi Steven,

Howdy,

I'm not a Ruby developer *at all*, I use Python, but this is not flame-
bait. I'm interested in how Ruby folks find using intervals.

I can only speak for myself.

In Python, we deal with integer ranges virtually exclusively with the
range() function. range() always results in a half-open interval:

range(5) => 0, 1, 2, 3, 4
range(1, 5) => 1, 2, 3, 4
range(4, -1, -1) => 4, 3, 2, 1, 0

The start argument is always included, the end argument is never
included, and there is an optional step size (defaults to 1).

I understand that in Ruby you have quite a few choices, some of which are
half-open like Python, some of which are closed:

0..5 => 0, 1, 2, 3, 4, 5
0...5 => 0, 1, 2, 3, 4

You need to write (0..5).to_a to get an array, though you don't need to convert it to an array for the usual kind of things like looping and choosing elements of an array.

5.downto(1) => 5, 4, 3, 2, 1
1.upto(5) => 1, 2, 3, 4, 5
5.times() => 0, 1, 2, 3, 4
5.step(11, 3) => 5, 8, 11

and the Range.new method.

No arrays here either (if that matters to you)

My question is: how useful are all these different mechanisms? Do you
find that having two operators .. and ... is a blessing, or a curse
because you can never remember which is which?

I had a look through about 25,000 lines of Ruby I working with now.

I've never used ..., only .. -- and then only for choosing parts of an array.

In my installed gems (about 60k lines but there are multiple versions of some libraries) this seems to happen in 6 files dealing with bigdecimals, telnet, http, webrick (a web server), and in an xml parser. The most interesting use is in a case statement handling HTTP error codes.

How useful are the closed interval forms? Do you find yourself making off-
by-one errors or needing to increment/decrement variables by one?

e.g. do you often need to write things like:

start.step(end + 1, increment){| i | block }
start.step(end - 1, increment){| i | block }

This does not appear in my code base. I habitually iterate over collections and arrays. I can't recall ever needing the a sequence of integers (except in benchmarks and tests)

Step shows up in the total code base I've got (roughly 80k lines) seven times, downto appears twice. Range.new shows up 4 times and in all cases with true for the third argument (i.e. equivalent to .. rather than ...)

Writing in Python, I almost never need to "shift the fence-posts", so to
speak. E.g. I virtually never need to write something like:

range(start, end+1)

I have had to do this once in the 25k lines: (3..(ARGV.length - 1)).each -- which, now that you've reminded me is better written (3...ARGV.length).each -- I'll change that now. Thanks.

to avoid an off-by-one error. When I used to program in Pascal (which
exclusively uses closed intervals) I used to need to do it all the time.
What's the Ruby experience?

In a few other languages this has definitely been something of an issue. Definitely.

Basically, I don't use that idiom, I iterate over collections. I think other Ruby programmers don't do that either.

Interesting. Thanks. Nice question.

Cheers,
Bob

···

On 24-Oct-07, at 9:45 PM, Steven D'Aprano wrote:

Thank you,

--
Steven

----
Bob Hutchison -- tumblelog at http://www.recursive.ca/so/
Recursive Design Inc. -- weblog at http://www.recursive.ca/hutch
http://www.recursive.ca/ -- works on http://www.raconteur.info/cms-for-static-content/home/

Steven D'Aprano wrote:

Howdy,
  
Hi
I'm not a Ruby developer *at all*, I use Python, but this is not flame-
bait. I'm interested in how Ruby folks find using intervals.

In Python, we deal with integer ranges virtually exclusively with the range() function. range() always results in a half-open interval:

range(5) => 0, 1, 2, 3, 4
range(1, 5) => 1, 2, 3, 4
range(4, -1, -1) => 4, 3, 2, 1, 0

The start argument is always included, the end argument is never included, and there is an optional step size (defaults to 1).

I understand that in Ruby you have quite a few choices, some of which are half-open like Python, some of which are closed:

0..5 => 0, 1, 2, 3, 4, 5
0...5 => 0, 1, 2, 3, 4
  

I nearly always use 0..5
Sometimes 0...5 in special cases.

5.downto(1) => 5, 4, 3, 2, 1
1.upto(5) => 1, 2, 3, 4, 5
5.times() => 0, 1, 2, 3, 4
5.step(11, 3) => 5, 8, 11
  
Rarely do I use these. And even then it's only 5.times do ... end

and the Range.new method.
  
Never.

My question is: how useful are all these different mechanisms? Do you find that having two operators .. and ... is a blessing, or a curse
  because you can never remember which is which?
  
Maybe it's just me, but I nearly always use .. so it's easy to remember that ... is the "special" case for me.

How useful are the closed interval forms? Do you find yourself making off-
by-one errors or needing to increment/decrement variables by one?

e.g. do you often need to write things like:

start.step(end + 1, increment){| i | block }
start.step(end - 1, increment){| i | block }
  
Never.

Writing in Python, I almost never need to "shift the fence-posts", so to speak. E.g. I virtually never need to write something like:

range(start, end+1)

to avoid an off-by-one error. When I used to program in Pascal (which exclusively uses closed intervals) I used to need to do it all the time. What's the Ruby experience?

Thank you,
  
Maybe I'm unusual (most of my code is for my own pet projects) but nearly all my iteration is done with arrays and hashes or objects that act like them, so my most commonly used loop construct is 'each'. After that it's probably 'until', then 'while', and 'times' last.

That's been my experience.

-Justin

I can only speak from my own experience.

I came to Ruby from Perl, so I knew .. and ... backwards and forwards.
There might have been a bit of a stumbling block when I was learning
Perl, but it's been so long that it all seems natural to me.

And speaking of Perl and "natural", much of that has to do with the
language's creator/designer being a linguist (or at least people like
to say so). When I came to Ruby, it felt like Matz took up that cause
and ran with it. For many problems, there are many, many solutions.
You choose which one works for you. Methods like Integer#times,
Integer#downto, Integer#upto, Numeric#step all have their uses.
Choosing the right one feels like choosing the right word to construct
a sentence.

···

On Oct 24, 8:45 pm, Steven D'Aprano <st...@REMOVE-THIS- cybersource.com.au> wrote:

I understand that in Ruby you have quite a few choices, some of which are
half-open like Python, some of which are closed:

0..5 => 0, 1, 2, 3, 4, 5
0...5 => 0, 1, 2, 3, 4

5.downto(1) => 5, 4, 3, 2, 1
1.upto(5) => 1, 2, 3, 4, 5
5.times() => 0, 1, 2, 3, 4
5.step(11, 3) => 5, 8, 11

and the Range.new method.

My question is: how useful are all these different mechanisms? Do you
find that having two operators .. and ... is a blessing, or a curse
because you can never remember which is which?

--
-yossef

My question is: how useful are all these different mechanisms? Do you
find that having two operators .. and ... is a blessing, or a curse
because you can never remember which is which?

Hi
i think it makes perfect sense to have those two options and with such a similar syntax. I had to think a second everytime to remember which is which, but i got used to it now. (Although it does not make much sense to me that three dots mean "less" than two dots.)

[...]. range() always results in a half-open interval:
range(1, 5) => 1, 2, 3, 4

I had to look up the terms "half-open" and "half-closed". Interval (mathematics) - Wikipedia says that an half-open interval (2,4] excludes 2, but includes 4. So in Python that would be half-closed intervals by default (right?), ikewise in Ruby.

I did not know upto() and downto() Uups.
Together with n.times they are just nice to have and you can use the one message that would be the most expressive, depending what you want to write.

What i find strage about ranges is that:
(0..3).to_a # => [0, 1, 2, 3]
but
(3..0).to_a # =>

Regarding the "off-by-one" question, i dont really know.

andreas

···

Am 25.10.2007 um 03:45 schrieb Steven D'Aprano:

Howdy,

I'm not a Ruby developer *at all*, I use Python, but this is not flame-
bait. I'm interested in how Ruby folks find using intervals.

In Python, we deal with integer ranges virtually exclusively with the
range() function. range() always results in a half-open interval:

range(5) => 0, 1, 2, 3, 4
range(1, 5) => 1, 2, 3, 4
range(4, -1, -1) => 4, 3, 2, 1, 0

The start argument is always included, the end argument is never
included, and there is an optional step size (defaults to 1).

I understand that in Ruby you have quite a few choices, some of which are
half-open like Python, some of which are closed:

0..5 => 0, 1, 2, 3, 4, 5
0...5 => 0, 1, 2, 3, 4

5.downto(1) => 5, 4, 3, 2, 1
1.upto(5) => 1, 2, 3, 4, 5
5.times() => 0, 1, 2, 3, 4
5.step(11, 3) => 5, 8, 11

and the Range.new method.

My question is: how useful are all these different mechanisms? Do you
find that having two operators .. and ... is a blessing, or a curse
because you can never remember which is which?

How useful are the closed interval forms? Do you find yourself making off-
by-one errors or needing to increment/decrement variables by one?

e.g. do you often need to write things like:

start.step(end + 1, increment){| i | block }
start.step(end - 1, increment){| i | block }

Writing in Python, I almost never need to "shift the fence-posts", so to
speak. E.g. I virtually never need to write something like:

range(start, end+1)

to avoid an off-by-one error. When I used to program in Pascal (which
exclusively uses closed intervals) I used to need to do it all the time.
What's the Ruby experience?

Thank you,

--
Steven

Steven D'Aprano wrote:

Howdy,

I'm not a Ruby developer *at all*, I use Python, but this is not flame-
bait. I'm interested in how Ruby folks find using intervals.

In Python, we deal with integer ranges virtually exclusively with the range() function. range() always results in a half-open interval:

range(5) => 0, 1, 2, 3, 4
range(1, 5) => 1, 2, 3, 4
range(4, -1, -1) => 4, 3, 2, 1, 0

The start argument is always included, the end argument is never included, and there is an optional step size (defaults to 1).

If there is only one kind of range to be supported (which I understand
to be in sync with the Python philosophy), I agree that half-open
intervals are the way to go.

I understand that in Ruby you have quite a few choices, some of which are half-open like Python, some of which are closed:

0..5 => 0, 1, 2, 3, 4, 5
0...5 => 0, 1, 2, 3, 4

The two different ranges are nice-to-have, because sometimes the closed
interval is the right thing to use. I'd have exchanged the syntax 'though.
Having said that, I have never had a problem distinguishing the two.

5.downto(1) => 5, 4, 3, 2, 1
1.upto(5) => 1, 2, 3, 4, 5
5.times() => 0, 1, 2, 3, 4
5.step(11, 3) => 5, 8, 11

--snip--

This is not really a range, but the Ruby Way of looping; it is what made me
fall in love with Ruby in the first place. For me, it is one the most
beautiful aspects of any programming language that I know.

Best regards,

Michael

I rarely use #downto, #upto and #step. I frequently use #times and ranges - usually the ".." version but sometimes also the other one. I never use Range.new.

Both range versions come in handy, for example, if you need to iterate through an array using an index counter then the triple dot is convenient because you do not need to to math:

for i in 0...ar.size
   puts ar[i]
end

#times is an alternative here

ar.size.times do |i|
   puts ar[i]
end

I think Justing pinpointed the major reason why these integer iterating constructs are less use in Ruby: collections are typically traversed via their #each method.

Kind regards

  robert

···

On 25.10.2007 03:43, Steven D'Aprano wrote:

Howdy,

I'm not a Ruby developer *at all*, I use Python, but this is not flame-
bait. I'm interested in how Ruby folks find using intervals.

In Python, we deal with integer ranges virtually exclusively with the range() function. range() always results in a half-open interval:

range(5) => 0, 1, 2, 3, 4
range(1, 5) => 1, 2, 3, 4
range(4, -1, -1) => 4, 3, 2, 1, 0

The start argument is always included, the end argument is never included, and there is an optional step size (defaults to 1).

I understand that in Ruby you have quite a few choices, some of which are half-open like Python, some of which are closed:

0..5 => 0, 1, 2, 3, 4, 5
0...5 => 0, 1, 2, 3, 4

5.downto(1) => 5, 4, 3, 2, 1
1.upto(5) => 1, 2, 3, 4, 5
5.times() => 0, 1, 2, 3, 4
5.step(11, 3) => 5, 8, 11

and the Range.new method.

My question is: how useful are all these different mechanisms? Do you find that having two operators .. and ... is a blessing, or a curse because you can never remember which is which?

How useful are the closed interval forms? Do you find yourself making off-
by-one errors or needing to increment/decrement variables by one?

e.g. do you often need to write things like:

start.step(end + 1, increment){| i | block }
start.step(end - 1, increment){| i | block }

Writing in Python, I almost never need to "shift the fence-posts", so to speak. E.g. I virtually never need to write something like:

range(start, end+1)

to avoid an off-by-one error. When I used to program in Pascal (which exclusively uses closed intervals) I used to need to do it all the time. What's the Ruby experience?

"Steven D'Aprano" <steve@REMOVE-THIS-cybersource.com.au> wrote in message
news:13hvt65e4d1vd0b@corp.supernews.com...

Howdy,

How useful are the closed interval forms? Do you find yourself making off-
by-one errors or needing to increment/decrement variables by one?

e.g. do you often need to write things like:

start.step(end + 1, increment){| i | block }
start.step(end - 1, increment){| i | block }

Writing in Python, I almost never need to "shift the fence-posts", so to
speak. E.g. I virtually never need to write something like:

range(start, end+1)

to avoid an off-by-one error. When I used to program in Pascal (which
exclusively uses closed intervals) I used to need to do it all the time.
What's the Ruby experience?

    They're obviously not used a lot but they can be useful.
    They're really for times when you know the start and end points of
indexing, rather than the start and length of indexing. My girlfriend in
highschool (who was wonderfully nerdy) was well aware of off-by-one errors
while not being a computer programmer (she was into math and physics and
went into engineering) because of problems like asking how many days someone
has stayed somewhere if they arrived on the 5'th and left on the 16'th. The
naive answer, of course, is 16 - 5 but, upon closer inspection, it would
actually be 16 - 5 + 1. Apparently, this pattern has happened to her more
than once 'cause it came up (somehow) and she brought alot of attention to
this fact, so much so that I still remember this and am relaying it to all
of you...
    So, in Python, if you wanted to access the fifth to sixteenth element in
an array, you'd need to do something like this:

for i in range(5, 16 + 1):
    array[i] # do something with this...

    Some people might be tempted to just stick 17 in there but I wouldn't...

Hi --

Howdy,

I'm not a Ruby developer *at all*, I use Python, but this is not flame-
bait. I'm interested in how Ruby folks find using intervals.

In Python, we deal with integer ranges virtually exclusively with the
range() function. range() always results in a half-open interval:

range(5) => 0, 1, 2, 3, 4
range(1, 5) => 1, 2, 3, 4
range(4, -1, -1) => 4, 3, 2, 1, 0

The start argument is always included, the end argument is never
included, and there is an optional step size (defaults to 1).

I understand that in Ruby you have quite a few choices, some of which are
half-open like Python, some of which are closed:

0..5 => 0, 1, 2, 3, 4, 5
0...5 => 0, 1, 2, 3, 4

5.downto(1) => 5, 4, 3, 2, 1
1.upto(5) => 1, 2, 3, 4, 5
5.times() => 0, 1, 2, 3, 4
5.step(11, 3) => 5, 8, 11

and the Range.new method.

My question is: how useful are all these different mechanisms? Do you
find that having two operators .. and ... is a blessing, or a curse
because you can never remember which is which?

They're both useful. Don't forget that a range is not really a
collection (though some ranges can masquerade as arrays) as a kind of
boolean inclusion tester. The exclusive version (...) is like having <
as well as <= as a comparison operator -- very handy :slight_smile:

As for the various methods above, I use times quite a bit, downto and
upto and step not all that often (but I wouldn't be surprised if there
are cases where I might have used them but didn't think of it).

How useful are the closed interval forms? Do you find yourself making off-
by-one errors or needing to increment/decrement variables by one?

e.g. do you often need to write things like:

start.step(end + 1, increment){| i | block }
start.step(end - 1, increment){| i | block }

Writing in Python, I almost never need to "shift the fence-posts", so to
speak. E.g. I virtually never need to write something like:

range(start, end+1)

to avoid an off-by-one error. When I used to program in Pascal (which
exclusively uses closed intervals) I used to need to do it all the time.
What's the Ruby experience?

It all depends where the endpoints are coming from. If I can control
the end one, then I don't have to change it. If I don't, then I do.
I don't think it's any different from any other such situation --
e.g.:

   items.each_with_index do |item,index|
     puts "Item #{index + 1}: #{item.description}"
   end

It's more about the problem space than the Ruby methods you're using.

David

···

On Thu, 25 Oct 2007, Steven D'Aprano wrote:

--
Upcoming training by David A. Black/Ruby Power and Light, LLC:
   * Advancing With Rails, Edison, NJ, November 6-9
   * Advancing With Rails, Berlin, Germany, November 19-22
   * Intro to Rails, London, UK, December 3-6 (by Skills Matter)
See http://www.rubypal.com for details!

I understand that in Ruby you have quite a few choices, some of which
are half-open like Python, some of which are closed:

...

My question is: how useful are all these different mechanisms? Do you
find that having two operators .. and ... is a blessing, or a curse
because you can never remember which is which?

How useful are the closed interval forms? Do you find yourself making
off- by-one errors or needing to increment/decrement variables by one?

Thank you for everyone who wrote back, all good food for thought.

Are there many (any?) good examples of where you need to iterate over an
integer count, rather than directly over a data structure?

···

On Thu, 25 Oct 2007 01:43:33 +0000, Steven D'Aprano wrote:

--
Steven

Howdy,

I'm not a Ruby developer *at all*, I use Python, but this is not flame-
bait. I'm interested in how Ruby folks find using intervals.

In Python, we deal with integer ranges virtually exclusively with the
range() function. range() always results in a half-open interval:

range(5) => 0, 1, 2, 3, 4
range(1, 5) => 1, 2, 3, 4
range(4, -1, -1) => 4, 3, 2, 1, 0

The start argument is always included, the end argument is never
included, and there is an optional step size (defaults to 1).

I understand that in Ruby you have quite a few choices, some of which are
half-open like Python, some of which are closed:

0..5 => 0, 1, 2, 3, 4, 5
0...5 => 0, 1, 2, 3, 4

5.downto(1) => 5, 4, 3, 2, 1
1.upto(5) => 1, 2, 3, 4, 5
5.times() => 0, 1, 2, 3, 4
5.step(11, 3) => 5, 8, 11

and the Range.new method.

My question is: how useful are all these different mechanisms? Do you
find that having two operators .. and ... is a blessing, or a curse
because you can never remember which is which?

i use both frequently. '...' is always leads to shorter code when complex iterations are done and, of course, lead to fewer off by one errors since ruby arrays are zero index based.

How useful are the closed interval forms? Do you find yourself making off-
by-one errors or needing to increment/decrement variables by one?

no. but i've fixed alot of code that has.

e.g. do you often need to write things like:

start.step(end + 1, increment){| i | block }
start.step(end - 1, increment){| i | block }

Writing in Python, I almost never need to "shift the fence-posts", so to
speak. E.g. I virtually never need to write something like:

range(start, end+1)

to avoid an off-by-one error. When I used to program in Pascal (which
exclusively uses closed intervals) I used to need to do it all the time.
What's the Ruby experience?

in my experience open intervals, in c, fortran, c++ and idl often lead to off by one errors but, that being said, i think it's less in fortran because it uses '1' based arrays. also, anyone whose has coded C has probably found 'off, length' to be less error prone and open intervals lend themselves more easily to that notion.

cheers.

a @ http://codeforpeople.com/

···

On Oct 24, 2007, at 7:45 PM, Steven D'Aprano wrote:
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

> My question is: how useful are all these different mechanisms? Do you
> find that having two operators .. and ... is a blessing, or a curse
> because you can never remember which is which?

I had a look through about 25,000 lines of Ruby I working with now.

I've never used ..., only .. -- and then only for choosing parts of
an array.

I used ... last week a couple times, for what that's worth.

In my installed gems (about 60k lines but there are multiple versions
of some libraries) this seems to happen in 6 files dealing with
bigdecimals, telnet, http, webrick (a web server), and in an xml
parser. The most interesting use is in a case statement handling HTTP
error codes.

> e.g. do you often need to write things like:
>
> start.step(end + 1, increment){| i | block }
> start.step(end - 1, increment){| i | block }

This does not appear in my code base. I habitually iterate over
collections and arrays. I can't recall ever needing the a sequence of
integers (except in benchmarks and tests)

Honestly, I think I *might* have seen #step before once, in a book.
I've definitely never seen it in production code that I can recall,
and I've definitely never used it myself. The idiom of iterating over
collections became very natural to me very quickly and I think it's
likely that this is the case for other Ruby programmers in general.

I don't know if this is an important part of programming in Python or
not. I've played with Python but everything like that, I think I did
with "for x in y" loops. (those were cool, by the way.) I did do a few
"for x in range(y)" loops, so I could see how it would matter.

in Ruby it's nearly **always**

collection.each {|foo| bar}

Even when you're dealing with a subset of the collection, or dealing
with the collection in subsets of X number, it's more like

collection.each { |foo| in_groups_of(bar) { baz }}

There's more than one way to do it, like in Perl, but in practice
people seem to gravitate to this particular way, to the exclusion of
other ways.

(By the way the syntax is pseudocode.)

···

--
Giles Bowkett

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
Tumblelog: http://giles.tumblr.com/

For iterating, I agree.

But for case expressions, I prefer the interval to be inclusive.
Example from the pickaxe book:

  kind = case year
         when 1850..1889 then "Blues"
         when 1890..1909 then "Ragtime"
         when 1910..1929 then "New Orleans Jazz"
         when 1930..1939 then "Swing"
         when 1940..1950 then "Bebop"
         else "Jazz"
       end

/gordon

···

On Thu, 25 Oct 2007 15:40:00 +0900, Michael Ulm wrote:

If there is only one kind of range to be supported (which I
understand to be in sync with the Python philosophy), I agree that
half-open intervals are the way to go.

--

"Andreas Haller" <andreashaller@gmail.com> wrote in message
news:0C1522C0-3313-4FE0-9846-077D70938EBF@gmail.com...

My question is: how useful are all these different mechanisms? Do you
find that having two operators .. and ... is a blessing, or a curse
because you can never remember which is which?

Hi
i think it makes perfect sense to have those two options and with such a
similar syntax. I had to think a second everytime to remember which is
which, but i got used to it now. (Although it does not make much sense to
me that three dots mean "less" than two dots.)

    I think of it as the shorter keyword being the one more often used. As
I'm sure you know, half open intervals are used far more often than closed
intervals...

    It's a little scary that they're so similar but do different things in
that it may be easy to mistake one for the other. It would be an annoying
typo bug to track down...

[...]. range() always results in a half-open interval:
range(1, 5) => 1, 2, 3, 4

I had to look up the terms "half-open" and "half-closed". http://
en.wikipedia.org/wiki/Interval_(mathematics) says that an half-open
interval (2,4] excludes 2, but includes 4. So in Python that would be
half-closed intervals by default (right?), ikewise in Ruby.

    I don't think that it would be half open, by default, in Python. More
like it will always be half open in Python.

What i find strage about ranges is that:
(0..3).to_a # => [0, 1, 2, 3]
but
(3..0).to_a # =>

    I find this strange, as well...
    Aside from breaking many lines of code, how bad would it be to change
it?

Both range versions come in handy, for example, if you need to iterate through an array using an index counter then the triple dot is convenient because you do not need to to math:

for i in 0...ar.size
  puts ar[i]
end

#times is an alternative here

ar.size.times do |i|
  puts ar[i]
end

>> letters = (0..9).map { |i| (?a + i).chr }
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
>> letters.each_index do |i|
?> puts letters[i]
>> end
a
b
c
d
e
f
g
h
i
j
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]

James Edward Gray II

···

On Oct 25, 2007, at 1:40 AM, Robert Klemme wrote:

If there is one thing Ruby gets right over every other language it's iteration/looping mechanisms.
they look strange at first, but use them a bit and the feel natural

···

On Oct 25, 2007, at 5:00 AM, Steven D'Aprano wrote:

On Thu, 25 Oct 2007 01:43:33 +0000, Steven D'Aprano wrote:

I understand that in Ruby you have quite a few choices, some of which
are half-open like Python, some of which are closed:

...

My question is: how useful are all these different mechanisms? Do you
find that having two operators .. and ... is a blessing, or a curse
because you can never remember which is which?

How useful are the closed interval forms? Do you find yourself making
off- by-one errors or needing to increment/decrement variables by one?

Thank you for everyone who wrote back, all good food for thought.

Are there many (any?) good examples of where you need to iterate over an
integer count, rather than directly over a data structure?

--
Steven

Are there many (any?) good examples of where you need to iterate over an
integer count, rather than directly over a data structure?

Fizzbuzz. Anything where the problem space involves integers. Ruby
collection iterating becomes very normal to you when you use it. Any
problem space which doesn't involve integers and does involve
collections you'll probably address with collections.

Also, strictly speaking, when you iterate over a collection, you're
interacting with the collection in an OO manner, while using integer
indices to access their contents sequentially probably violates the
Law of Demeter or something. I want to avoid flame wars, especially
since if there was a flame war about that, it'd be Ruby & Smalltalk
vs. the universe, but the point seems valid. Getting into
implementation instead of just telling the object "do this, I don't
care how."

···

--
Giles Bowkett

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
Tumblelog: http://giles.tumblr.com/

yes. the most obvious one is needing adjacent entries and/or self-modification. something along the lines of

pixels.size.times do |i|
   pixel = pixels[i]
   left = pixels[i - 1]
   right = pixels[i + 1]

   if left.nil? and condition(right) or
      condition(left) and condition(right) or
      condition(left) and right.nil?

     pixel = transformation left, pixel, right
   end
end

granted, i personally would create my own neighborhood iterator for such a case - but then sometimes you need to compare adjacent neighborhoods...

i would go so far as to say *any* interesting algorithm can require random access into a data structure that's also being modified. in those cases iterating by size is a smart alternative since very few data structures in ruby support modification + traversal.

another good use case is

min = [a.size, b.size].min

min.times do |i|
   something_with a[i] and b[i]
end

which is to say iterating datasets in parallel.

yes there is zip - fantastic if you are into duplicating both datasets in memory *and* are iterating over n=2 data structures but otherwise useless.

that said - i'll take #each or #map any day.

cheers.

a @ http://codeforpeople.com/

···

On Oct 25, 2007, at 4:00 AM, Steven D'Aprano wrote:

Are there many (any?) good examples of where you need to iterate over an
integer count, rather than directly over a data structure?

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

hey, cool. Ruby has "for x in y" too. I had forgotten about that.

···

--
Giles Bowkett

Blog: http://gilesbowkett.blogspot.com
Portfolio: http://www.gilesgoatboy.org
Tumblelog: http://giles.tumblr.com/

James Edward Gray II wrote:

···

On Oct 25, 2007, at 1:40 AM, Robert Klemme wrote:

Both range versions come in handy, for example, if you need to iterate through an array using an index counter then the triple dot is convenient because you do not need to to math:

for i in 0...ar.size
  puts ar[i]
end

#times is an alternative here

ar.size.times do |i|
  puts ar[i]
end

>> letters = (0..9).map { |i| (?a + i).chr }
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]
>> letters.each_index do |i|
?> puts letters[i]
>> end
a
b
c
d
e
f
g
h
i
j
=> ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]

What was that example meant to show? Must be something other than this:

puts ("a".."j").to_a

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407