Skip to main content
Logo image

Problem Solving with Algorithms and Data Structures using Kotlin The Interactive Edition

Section 1.12 Control Structures

As we noted earlier, algorithms require two important control structures: selection and iteration. Kotlin supports both of these in various forms. Programmers can choose the statement that is most useful for the given circumstance.

Subsection 1.12.1 Selection

Subsubsection 1.12.1.1 if...else statements

Selection statements allow programmers to ask questions and then, based on the result, perform different actions. Most programming languages provide two versions of this useful construct: the if...else and the if. The following code fragment is an example of a binary selection using the if...else statement.
import kotlin.math.sqrt

fun main() {
    print("Enter a number: ");
    val n = readln().toDouble()

    if (n >= 0) {
        println(sqrt(n))
    } else {
        println("Number can not be negative.")
    }
}
In this example, the value of variable n is checked to see if it is greater than or equal to zero. If it is, the program prints the square root of the number. If it is not, the statement performs the else clause and tells the user that the number cannot be negative.
The condition for the if must be enclosed in parentheses. The body of the if and else clause is enclosed in braces. If there is exactly one statement in the clause, you may omit the braces, but doing so may lead to code that is ambiguous and difficult to read. Thus, we strongly recommend that you always use braces (with one exception that we will cover later).
Selection constructs, as with any control construct, can be nested so that the result of one question helps decide whether to ask the next. For example, consider this program to determine the grade based on the score for a computer science test.
Listing 1.12.1. Score conversion program.
fun main() {
    print("Enter a score: ");
    val score = readln().toInt()

    var grade = ""

    if (score >= 90) {
        grade = "A"
    } else {
        if (score >= 80) {
            grade = "B"
        } else {
            if (score >= 70) {
                grade = "C"
            } else {
                if (score >= 60) {
                    grade = "D"
                } else {
                    grade = "F"
                }
            }
        }
    }

    println("The grade is $grade.")
}
This program will classify a value called score by printing the letter grade earned. If the score is greater than or equal to 90, the variable grade will be assigned "A". If it is not (else), the next question is asked. If the score is greater than or equal to 80, then it must be between 80 and 89 since the answer to the first question was false. In this case, the grade becomes "B" is printed. You can see that using correct indentation pattern helps to make sense of the association between if and else.
The drawback of this indentation is that the code tends to march off the page to the right, which does not help readability. We can, however, consider the block in lines 6-18 as a single statement, and use the β€œomit braces” shortcut. Similarly, we can eliminate braces around the statement in lines 8-17 and so on. We can then follow the else immediately by an if with the resulting code:
Listing 1.12.2. Score conversion, with good indentation.
fun main() {
    print("Enter a score: ");
    val score = readln().toInt()

    var grade = ""

    if (score >= 90) {
        grade = "A"
    } else if (score >= 80) {
        grade = "B"
    } else if (score >= 70) {
        grade = "C"
    } else if (score >= 60) {
        grade = "D"
    } else {
        grade = "F"
    }

    println("The grade is $grade.")
}
Note that the final else is still necessary to provide the default case if all other conditions fail.

Subsubsection 1.12.1.2 else is optional for if statements

The else clause is not required in Kotlin; an if without an else is called a single-way selection construct. In a single-way selection, if the condition is true, an action is performed. When the condition is false, processing simply continues on to the next statement after the if. For example, the following fragment will first check to see if the value of a variable n is negative. If so, then it is modified by the absolute value function. Regardless, the next action is to compute the square root.
import kotlin.math.abs
import kotlin.math.sqrt

fun main() {
    print("Enter a value: ");
    var n = readln().toDouble()
    if (n < 0) {
        n = abs(n)
    }

    println(sqrt(n))
}

Subsubsection 1.12.1.3 if expressions

Look again at the score assignment example shown above in ListingΒ 1.12.2. In every single case, we assign a value to the variable grade. Kotlin provides an if expression that we can use to make the code a bit briefer:
Listing 1.12.3. Score conversion, with if expression.
fun main() {
    print("Enter a score: ");
    val score = readln().toInt()

    val grade = if (score >= 90) {
        "A"
    } else if (score >= 80) {
        "B"
    } else if (score >= 70) {
        "C"
    } else if (score >= 60) {
        "D"
    } else {
        "F"
    }

    println("The grade is $grade.")
}
In this version, if is an expression that returns a value, which is then assigned to the variable grade. Again, this version if if is useful when every case assigns a value to the same variable. This form requires that there be an else case.

Subsubsection 1.12.1.4 when statements and expressions

When we have an if...else statement or expression where at every step we check the same variable for equality to different values, we can use a when statement or expression instead. when results in slightly briefer code than if in this situation. Here are two examples with similar behavior, one using when as a statement, and one using it as an expression.
Listing 1.12.4. Grade conversion, with when statement.
fun main() {
    print("Enter a letter grade: ");
    val grade = readln()

    var score = 0

    when (grade) {
        "A" -> score = 90
        "B" -> score = 80
        "C" -> score = 70
        "D" -> score = 60
        else -> score = 0
    }

    println("The grade was at least $score")
}
Listing 1.12.5. Grade conversion, with when expression.
fun main() {
    print("Enter a letter grade: ");
    val grade = readln()

    val score = when (grade) {
        "A" -> 90
        "B" -> 80
        "C" -> 70
        "D" -> 60
        else -> 0
    }

    println("The grade was at least $score")
}

Subsection 1.12.2 Iteration

For iteration, Kotlin provides a standard while statement and a very powerful for statement. The while statement repeats a body of code as long as a condition evaluates to true. Generally, we use a while loop for indeterminate loops, where we do not know how many times the loop has to iterate. Consider this program, where we ask the user repeatedly enter numbers they want to sum, entering zero when they are finished. In this case, we have no idea how many times the user will enter numbers before finishing:
fun main() {
    var sum = 0.0

    print("Enter a number, or zero to quit: ")
    var n = readln().toDouble()
    while (n != 0.0) {
        sum = sum + n
        print("Enter another number, or zero to quit: ")
        n = readln().toDouble()
    }

    println(String.format("The sum is %.3f%n", sum))
}
The condition on the while statement is evaluated at the start of each repetition. If the condition evaluates to true, the body of the statement will execute. While Kotlin does not require you to indent the body of the loop, we strongly suggest you do so to make your code more readable.
The while statement is a very general-purpose iterative structure that we will use in a number of different algorithms. In many cases, a compound condition will control the iteration. Consider the following variation of the above program, which will also stop when the sum goes over 10:
Listing 1.12.6. Example of while loop
fun main() {
    print("Enter a number, or zero to quit: ")
    var n = readln().toDouble()
    var sum = n

    while (n != 0.0 && sum < 10) {
        print("Enter another number, or zero to quit: ")
        n = readln().toDouble()
        sum = sum + n
    }

    println(String.format("The sum is %.3f%n", sum))
}
The compound condition would cause the body of the statement to be executed only in the case where both parts of the condition are satisfied.
Sometimes, though, we do know how many iterations a calculation will require. We can use the for loop in conjunction with many of the Kotlin collections to iterate over the collection’s members. So, for example,
for (item in listOf(1, 3, 6, 2, 5)) {
    println(item)
}
assigns the variable item to be each successive value in the list [1, 3, 6, 2, 5]. The body of the iteration is then executed. This results in the following output:
1
3
6
2
5
This works for any collection that provides iteration capability; this includes lists and strings, among others.
A common use of the for statement is to implement definite iteration over a range of values. The statement
for (item in 0 ..< 5) {
    println(item * item)
}
will perform the println function five times. The expression 0 ..< 5 returns a range object representing the sequence 0, 1, 2, 3, 4 and each value will be assigned to the variable item. This value is then squared and printed.
Kotlin has a variety of options in range expressions. Most notably, the range 0 .. 5 (without the <) is inclusive on both ends: it represents the sequence 0, 1, 2, 3, 4, 5. Here are some other examples:
  • 0 ..< 5 step 2 : sequence starting at 0, ending with 4, each item increasing by 2
  • 5 downTo 1: sequence starting at 5, ending at 1, each item decreasing by 1
Another useful version of this iteration structure is used to process each character of a string. The following program iterates over a list of strings and for each string processes each character by appending it to a list. The result is a list of all the letters in all of the words.

Exercises 1.12.3 Self Check

1.

Write a Kotlin program that uses a while loop to continually prompt the user to enter a number greater than zero until the user does so. (Hint: as long as the number is not greater than zero, you must keep asking.)

2.

Here are five scores for a student’s assignments: 98.2, 85.9, 94.0, 92.0, 88.5. The weight of each assignment is 0.3, 0.2, 0.3, 0.1, 0.1 (that is, the first assignment is worth 30% of the total grade, the second is worth 20%, and so on). Write a program which calculates a weighted sum by multiplying each score by its corresponding weight and summing them up. Your program must use a for loop.

3.

Write a Kotlin program that takes a list of integers and produces the sum of the odd-indexed numbers and the sum of the even-indexed numbers. For example, in the list [4, 2, 8, 5, 9], the even-numbered index elements are 4, 8, and 9, which add up to 21. The odd-numbered index elements are 2 and 5, which sum to 7. Your program must work with any list, not just this example list. Try to do it with only one loop (hint: if is your friend).
You have attempted of activities on this page.