Stop using the for loop 10

Posted by jeff Saturday, October 22, 2005 02:18:00 GMT

As a longtime C++ and C# developer I have a lot of coding traditions that I don’t realize I have until I’m in the middle of writing some code in, say, a controller action, and I have to think, Oh God, how do I do this in Ruby? I know how I would do it in C# – but how do I do this in Ruby?

One example that really started to break the ice for me and get me on the Ruby train is Ruby’s answer to the typical “for” loop. You know, it goes something like this in C#:

for (int i=0; i < total; ++i)
{
  // do something here 
}

And once upon a time I used to get confused about how to write the ending condition. Is it i < total or i <= total? And so on.

Well, fellow C++/C# softies that are now on Rails, heed this advice: STOP WRITING FOR LOOPS. Yes, you heard me. Stop it right now. There are better ways in Ruby to loop over some code. Let’s look at the most common ways.

A great one to start learning is times. When you just want to repeat something a given number of times, well, just do so:

10.times { puts "hockey" }

will print “hockey” ten times.

But wait, it gets better. Suppose you want to know which iteration you’re on. You can either do this:

10.times { |n| puts n }

which will print the numbers 0 through 9, or mayabe you want to do this:

5.upto(9) { |n| puts n }

which will print the numbers 5 through 9, inclusive. Write the equivalent C++ code and tell me which is easier to read, hmmm?

Ok, so now for something you’re likely to do quite a bit in your actions and views. Suppose you have an array and want to loop over the values in the array. In C#, it’s like this:

foreach (Object obj in myList)
{
  // do something with obj
}

In Ruby, do this:

myList.each do |obj|
 # do something with obj
end

or, if you just can’t wean yourself from that three-letter keyword, Ruby does provide a syntactical sugar alternative:

for obj in myList do
 # do something with obj
end

So there you have it, lots and lots of ways to loop over stuff in Ruby that’s more intuitive and flexible than what we used to do in that other language.

Comments

Leave a response

  1. Lazaro Cardenas Michoacan Mexico   April 29, 2006 @ 04:51 PM

    Gonna have to give it a try :(

  2. Ernesto   June 15, 2006 @ 01:11 PM

    And what am I supposed to do in a case like this?

    for(int i = 0; i < arr.Length; ++i) arr[i] = 3*i;

    that is, I don't want just to iterate over the values in the array, but to modify them instead.

    In other words, you told us how to know at which position of an iteration we are with the .times method. But how can we know at which position of an iteration we are in the .each iterator, or the "for obj in arr do" loop?

  3. Jeff   June 15, 2006 @ 03:02 PM

    Hi Ernesto. Good question, with an easy answer. Just use .each_with_index instead of .each, like this:

    arr.each_with_index do |obj, i| obj = 3*i end

    each_with_index will provide you with two parameters, the object and the index for the current iteration.

    For a quick reference to everything the Enumerable module offers, check out http://ruby-doc.org/core/classes/Enumerable.html. (The Array class "mixes in" the Enumerable module, that's why arrays have .each_with_index).

    Make sense? Let me know.

    Jeff

  4. RSL   July 05, 2007 @ 06:23 PM

    For anyone reading this from a Google search, Enumerable#collect was made for the scenario Ernesto describes.

    [1, 2, 3].collect{|x| x * 3} => [3, 6, 9]

    Simple as pie and as yummy too! Enumerable has a lot of really useful methods and I encourage new Rubyists to check them all out.

  5. Jeff   July 06, 2007 @ 05:17 PM

    RSL, I think Ernesto was wanting to modify the array in place, which collect won't do, so that's why I pointed him to each_with_index.

    But you're right that .map and .collect are not appreciated as much as they should be, so thanks for pointing that out.

  6. Mel Ram   December 27, 2007 @ 03:47 AM
    I spent 1/2 hr today to debug a stupid for loop in rails today. I am a beginner at rails and I was trying to figure out how to do a for loop with an array and I had most of the code right except... lets see if you can figure it out (heehee):
    
    
      <% Dir.glob('*').each do |i| %>
    • <%= i%>
    • <% end %>
  7. Mel Ram   December 27, 2007 @ 03:55 AM

    delete other version. keep this one.

    I spent 1/2 hr today to debug a stupid for loop in rails today. I am a beginner at rails and I was trying to figure out how to do a for loop with an array and I had most of the code right except... lets see if you can figure it out (heehee):

      <% Dir.glob('*').each do |i| %>
    • <%= i%>
    • <% end %>
  8. kino   May 24, 2008 @ 01:11 AM

    The manifold (and it must not be supposed that this is true) has lying before it the paralogisms of pure reason; however, the discipline of natural reason can thereby determine in its totality, in accordance with the principles of the paralogisms, the things in themselves.

  9. Ellroy   May 30, 2008 @ 11:22 PM

    Natural causes have nothing to do with, even as this relates to the employment of natural causes, philosophy; on the other hand, the Antinomies can be treated like the employment of our a priori concepts.

  10. loans82   September 02, 2008 @ 11:06 PM

    hey !! its very reasonable article. Good post. realy good post

    thank you ;)

Comment


(won't be published)