This is a shallow tutorial about loops for programming beginners (as my wife). It should get you kick-started but please don’t stop here. There’s a lot more to explore.
I chose JavaScript since you can run it right here in your browser’s dev tools (CTRL+SHIFT+i in most browsers, then choose console).
There might be some things in the code examples that don’t make sense to you yet. Just note them down and don’t fall into the rabbit just yet. I provide some extra hints and rabbit holes. Try to sweep over this once without following the white rabbit to focus on the topic.
Prerequisites:
- you want to learn this stuff – at least at a practical level
- you’ve seen JavaScript (JS) before
- you’ve read the term iteration before
- you have at least an idea what some of these mean: collection, set, list, vector, array, iterable
- you know basic data types such as Booleans
Aight, let’s start with a problem. Let’s say you program a little game for a set of players. There’s Tom, Anne and Jane. You want to greet them before explaining the rules. That’s easy:
console.log('Hi Tom, Anne and Jane.')
Fair enough. Now think you have twenty players. Things start to get a little tedious but that’s still managable. Alright.
Now think you want to open this up to an unknown set of players. At the time you write your program you don’t know how many players there will be nor their names. Now how do you solve this problem?
Take a moment to figure something out.
…
.
.
.
Right, how could the answer not have been „loops“?
There’s pretty much two and a half types of loops in almost all languages and they come in some differen flavours.
A loop consists of some condition or control structure and a body. The body gets executed over and over again as long as the condition holds. In C-style languages the basic form is some keyword(s) (condition in parantheses) {body in curly braces}.
First there is the while loop. It keeps executing it’s body as long as a given expression stays true (and you do not break out of it).
As long as there’s dirty dishes:
____do the dishes
or:
While there are dirty dishes:
____wash
____rinse
Let’s see how it can solve our problem:
alert("Who's playing? Type in player names one after another. Type 'done' when you're done.")
let players = []
let isDone = false
while (!isDone) {
let player = prompt('Who are you?')
if (player === 'done')
isDone = true
else
players.push(player)
}
alert('Hello ' + players.join(', '))
What happens here? As long as we are not done (isDone
is false
), we will keep asking for player names. If the user types in done
we will set isDone
to false and the next time the loop’s condition is checked it will evaluate to false and the program flow will continue past the loop’s body. In JS and many other languages the form is „while (condition) { stuff to do as long as condition holds }„.
Hint: For one-lines you can omit the curly braces.
Hint: There’s often also do-while of the form „do { stuff } while (condition)“ or do-until where the first iteration of the loop is executed before the condition is checked. Can be handy but you won’t see it often.
Rabbit Hole: In sane languages, code outside the loop’s body has no access to things declared inside of it.
Great! Now try to output the collected player names with a while loop.
…
Let’s continue with the classic for loop. It is the same as the while loop but with some handy extras. It also keeps executing it’s body as long as a condition holds. But it allows you to declare and initialize a variable and to provide a statement to be executed after each iteration. The common form is „for (initializer; condition; post-loop-statement) { stuff to be repeated }“.
A speed date:
For: pour in one glass of wine; not more than ten in total; refill after each round:
____have a conversation
____drink wine
____move to next table
Let’s see it in action:
players = []
let numPlayers = prompt('How many players are there?')
alert("Who's playing? Type in player names one after another.")
for (let i = 0; i < numPlayers; i++) {
players.push(prompt('Who are you?'))
}
alert('Hello ' + players.join(', '))
Rabbit Hole: See JS‘ variable declaration to understand what let
does here.
What’s going on here? We first ask for the number of players. Then, we execute the loop’s body this many times. We declare a variable i
and initialize it to zero. This is only done once, before the loop’s body executes. The next thing that happens is that the loop’s condition gets checked. If you entered five, for example, 0 < 5
holds and the body gets executed. After that, the post-iteration statement gets executed (i++
in this case is the same as i = i + 1
) and i
will be incremented by one. It is now 1 (0 + 1). The condition still holds so we go for another round and so on until 5 < 5
evaluates to false
. What values does i
take one after another?
…
0, 1, 2, 3, 4.
You could as well have started at 1 and chosen i <= 5
as your condition. Or i < 6
. You could have chosen 5 as initial value for i
and counted down: for (let i = 5; i > 0; i--);
. Or you could have counted until 10 with two-step increments. In our case the value of i
only matters for the condition and we want to run the body five times.
But this loop style comes in handy when you have a reason to know that it’s currently the nth
iteration of the loop. Let’s change our example a little with emphasis on the first and last players:
players = []
numPlayers = prompt('How many players are there?')
alert("Who's playing? Type in player names one after another.")
for (let i = 0; i < numPlayers; i++) {
if (i == 0)
players.push(prompt("Who's first?"))
else if (i == numPlayers - 1)
players.push(prompt("And finally:"))
else
players.push(prompt("Who else?"))
}
alert('Hello ' + players.join(', '))
The first and last player now get a special prompt.
Try to output the player names by using a for loop.
…
But what if you don’t care about if it’s the first, second, or one millionths iteration? Do you always have to jump through all the calculation hoops? Of course not. There’s another flavor of the for loop, often called foreach, for-in, or for-of. It (usually) iterates over something you (the computer) knows the size of. Let’s use it to output the player’s names:
players = []
numPlayers = prompt('How many players are there?')
alert("Who's playing? Type in player names one after another.")
for (let i = 0; i < numPlayers; i++) {
players.push(prompt("Who is it?"))
}
for (let player of players) {
alert('Hello ' + player)
}
This is way less to type and to think about. You can read it as „for each x of some collection y do z“ where x
is substituted with one value of y
after another within your loop’s body z
.
Can you do the name-prompting loop with this type of loop? Don’t worry if you can’t but give it a try.
…
If you failed to do it there’s a reason for it. There’s a reason we have different types of loops – because they are useful in different situations. But still, they are (usually) equivalent. You can do the same things with them.
for (let x of Array(5))
players.push(prompt("Who is it?"))
Here’s another one for the classic for loop:
numPlayers = prompt('How many players are there?')
players = []
alert("Who's playing? Type in player names one after another.")
for (let i = 0; i < numPlayers; i++) {
players[i] = (prompt("Who is it?"))
}
alert('Hello ' + players.join(', '))
We set the ith
element of the array to to current value.
When to choose which?
Use while for unknown sizes or non-countable cases.
Use classic for when the current index matters.
Use foreach for limited collections, when only the values matter – or if your language supports it for key-value cases, too.
In reality you will probably most often iterate over some known set (maybe unbounded) and a foreach loop is usually most concise.
Bonus: break and continue
You can either break out of the loop’s body at any time via the break
keyword or skip one iteration via the continue
keyword.
alert("Who's playing? Type in player names one after another. Type 'done' when you're done. Note that no Bobs are allowed to play. Sorry Bob.")
let players = []
while (true) {
let player = prompt('Who are you?')
if (player === 'done')
break
else if (player.toLowerCase() === 'bob') {
alert('I said NO BOBS!')
continue
}
else
players.push(player)
}
alert('Hello ' + players.join(', ') + ' ... and no Bob')
Bonus: You don’t need the initializer and post-iteration clause for the classic for loop. Actually not even the condition, it’s implicitly true
. for (;;) break
is perfectly fine. Or for (;;);
– but you shouldn’t run it. What would happen if you did?
There’s more to it but these building blocks should make you „Turing complete“ already. You can nest loops, mostly do whatever you want inside their bodies or compute all the prime numbers … if you have some spare time. As a final task, do compute the prime numbers between 1 and a given number. It doesn’t have to be efficient, just make it work.
…
let upperLimit = prompt('Upper limit, > 1')
let primes = [1]
for (let i = 2; i <= upperLimit; ++i) {
let halfI = i / 2
let isPrime = i % 2 != 0
if (isPrime)
for (let j = 2; j <= halfI; ++j) {
if (i % j == 0) {
isPrime = false
break
}
}
if (isPrime)
primes.push(i)
}
console.log(primes)
Rabbit Hole: Look into FRP, things like map, filter, reduce, folding, streams.