DEV Community

loading...

Ruby Loops

bmweygant profile image Brandon Weygant Updated on ・5 min read

Today we're going to go over the concept of looping in Ruby. Looping is an action that tells our program to do the same thing over and over again with a few lines, rather than manually typing out our desired loop length.

Why Loop?

Simple answer: because as programmers we aspire to be as lazy as possible.

Think a minute about writing a program that requires you to perform an action 5 times, then imagine having to do it 100 times. What problems could you potentially run into typing all occurrences manually? First is a matter of convenience, even if you copy/paste to ensure all the lines are exactly the same, that's still a tedious manual task that takes away time from improving your program elsewhere. Next, what if you lose count after say 47? What if you accidentally type it in only 97 times? 103 times? This could potentially cause your program to not work as intended in other parts of your code as well.

Loops automate this process for us with only a couple lines of code in Ruby. A program that would require a String to be repeated 100x would use 100+ lines of code if manually looped. You can perform the same functionality in Ruby with about 3 lines of code:

100.times do
  puts "Here we go 'round!"
end
Enter fullscreen mode Exit fullscreen mode

And just like that, a seemingly daunting task is complete in a matter of seconds!

Ruby has several different types of loops, some with overlapping functionality and some meant to be more niche in use. We'll go over some of the more common types of loops and explain them in greater detail below.

Times Loops

Let's start by breaking down the above loop, and highlight the keys that make this function:

100.times do
  puts "Here we go 'round!"
end
Enter fullscreen mode Exit fullscreen mode
  1. 100.times is the number of times we want our program to perform the following action. The number in front of times also serves as a built-in break of the loop, where some other loop types require you to add it in elsewhere.
  2. the do/end creates a block that tells our program what action we want to perform. In this case puts "Here we go 'round!" The do/end block will be a common participant in a number of Ruby lessons.

The beauty of Ruby is it's designed with being programmer-friendly as it's #1 priority. times is one of the best examples of that in the entire language.

The "Loop" Keyword

Next up is the loop keyword. loop is the simplest construct we have for looping in Ruby. It will just execute a block (the action(s) between do/end) over and over until it is told to stop.

Let's built a similar method as above from scratch:

loop do
  puts "Here we go 'round!"
end
Enter fullscreen mode Exit fullscreen mode

This will put the string "Here we go 'round!" into our console in an eternal loop until we stop it with ctrl+c. Not terribly useful overall in its current form if you ask me. Let's add a break command to stop the loop on its own:

loop do
  puts "Here we go 'round!"
break
end

# returns =>
#Here we go 'round!
Enter fullscreen mode Exit fullscreen mode

So now we have a "loop" that only executes our desired command once. The thing is loop is so simple, that it requires a bit more effort to work at the same level as times, which kind of defeats the point as Rubyists.

If we wanted to write a loop command equivalent to our times command above, we would have to add a counter to keep track of when to break the loop like such:

counter = 0
loop do
    counter += 1
    puts "Here we go 'round!"
    if counter >= 100
        break
    end
end
Enter fullscreen mode Exit fullscreen mode

That is almost triple the number of lines it took our times loop to accomplish the same task.

Note You may be wondering what the += is doing. It basically performs the same function as the line counter = counter + 1 which increments and keeps track of the updated value of the counter variable. It simply condenses the code.

Since we have a counter variable, I'll take this opportunity to demonstrate how to keep track of variables inside loops. Stop me if this looks familiar to you:

counter = 0
loop do
    counter += 1
    puts "Here we go 'round #{counter} times!"
    if counter >= 100
        break
    end
end
#returns =>
#Here we go 'round 1 times!
#Here we go 'round 2 times!
#...
#Here we go 'round 99 times!
#Here we go 'round 100 times!
Enter fullscreen mode Exit fullscreen mode

Yup, we can interpolate with #{variable} inside loops to display and even manipulate the current values of variables.

While Loops

while loops provide a unique approach to a similar end. Basically while translates the given condition to a boolean, and if that condition is true the while loop will then execute until the condition is false. Like times while is it's own built-in break, so there is no need to declare a direct break inside the action like with loop. Writing a loop like above in this style would look like this:

counter = 0
while counter < 100
  puts "Here we go 'round!"
counter += 1
end
Enter fullscreen mode Exit fullscreen mode

Removing the break command saves us some space, but in a strict counting situation while still isn't as advantageous as the times loop. However, in slightly more complex programs, while has some strong advantages over times. For example, if we had an adventurer who was poisoned and losing health, we would want to keep track of our HP so we know when to use our auto-revive potions, right? And we would definitely need a reminder to pop up when we died from the poison too, right?

hp = 100
status = "poisoned"
potions = 2

while status == "poisoned" && hp >= 1
    hp -= 1
    puts "HP: #{hp}"
    if hp == 0 && potions >= 1
        puts "You've used an auto-revive potion!"
        potions -= 1
        hp += 100
        status = "normal"
        puts "HP: #{hp}"
    elsif hp == 0 && potions == 0
        puts "The poison was too much to bear!"
    end
end
Enter fullscreen mode Exit fullscreen mode

This code is a bit busy, but doesn't contain anything we haven't covered already! The gist is we set initial values for hp, status. & potions and manipulated them throughout the while loop. Using times in this situation would require multiple loops and more lines for what would likely be a less desirable result. Also note the do in while is not necessary

On a more personal note, I'm glad we had enough potions to survive being poisoned!

Until Loops

unitl is basically the inverse of while. Where a while loop executes when something is true, an unitl loop will execute until something becomes true. For example:

counter = 0
until counter == 20
  puts "Almost 20!"
  counter += 1
end
Enter fullscreen mode Exit fullscreen mode

Just like while the do is optional.

While you can do complex code with until, in my opinion, the best time to use until is as a statement modifier. Example:

i = 0
puts i += 1 until i == 5

#returns =>
#1
#2
#3
#4
#5
Enter fullscreen mode Exit fullscreen mode

This is a very simple example, but it does an effective job of manipulating the value of a variable to the desired number in only 1 line of easy to read code.

Concluison

The key to loops in Ruby, and any programming language really, is knowing what loop is best used in a given situation. Do you want to repeat an action a specific amount of times with little additional context? Use times!. Want to drown someone special in your eternal love? Use loop (with no break!)! Wanna get a little more complex with your code? Use while! Need a simple and precise statement modifier? Use until!

Loops Lab

Now that you've learned about Loops, let's head on over to the Ruby Loops Lab and apply those lessons by completing the assigned tasks.

Discussion (0)

pic
Editor guide