Control Flow Workbook
Eleven short exercises on Kotlin control flow — if as an expression, ranges, for loops, membership with in, indices, and labelled break.
Practice problems for Kotlin’s if Returns a Value, So There’s No Ternary. Each takes a minute or two. Some exercises auto-check: implement the function in the editor and press Run — hidden tests go green when you’re right and red (with a hint) when you’re not, all on JetBrains’ Kotlin compiler server. The printing and range exercises stay attempt-then-reveal: press Run to try them, then click Show answer. Nothing here is a trick question, just direct practice of the syntax from the lesson.
if as an expression
1. Assign from an if
Implement grade so it returns "pass" when score > 50, otherwise "fail" — using if as an expression.
import org.junit.Test
import org.junit.Assert
class Test {
@Test fun grades() {
Assert.assertEquals("pass when score is above 50",
"pass", grade(60))
Assert.assertEquals("fail at exactly 50",
"fail", grade(50))
}
}
//sampleStart
fun grade(score: Int): String =
"fail" // TODO: "pass" when score > 50, else "fail"
//sampleEnd Show answer Hide answer
fun grade(score: Int) = if (score > 50) "pass" else "fail" 2. No ternary needed
Implement sign — the Kotlin form of the Java expression x > 0 ? "+" : "-".
import org.junit.Test
import org.junit.Assert
class Test {
@Test fun signs() {
Assert.assertEquals("plus when x is positive",
"+", sign(3))
Assert.assertEquals("minus when x is negative",
"-", sign(-3))
Assert.assertEquals("minus at zero",
"-", sign(0))
}
}
//sampleStart
fun sign(x: Int): String =
"-" // TODO: "+" when x > 0, else "-"
//sampleEnd Show answer Hide answer
fun sign(x: Int) = if (x > 0) "+" else "-" Ranges
3. Two ranges
Write a range covering 1 through 10 inclusive, and one covering 1 through 9 (excluding the upper end).
fun main() {
val inclusive = 1..10 // 1 through 10 inclusive
val exclusive = 1..10 // TODO: 1 through 9 — use 'until'
println(inclusive.toList())
println(exclusive.toList())
} Show answer Hide answer
1..10
1 until 10 4. Count down
Print 5, 4, 3, 2, 1 with a single for loop.
fun main() {
// TODO: print 5, 4, 3, 2, 1 — one loop
for (i in 1..5) println(i)
} Show answer Hide answer
for (i in 5 downTo 1) println(i) 5. Every other number
Print 0, 2, 4, 6, 8, 10 with a single for loop.
fun main() {
// TODO: print 0, 2, 4, 6, 8, 10 — one loop
for (i in 0..10) println(i)
} Show answer Hide answer
for (i in 0..10 step 2) println(i) 6. A range membership check
Implement working — true when age is between 18 and 65, both inclusive.
import org.junit.Test
import org.junit.Assert
class Test {
@Test fun inRange() {
Assert.assertTrue("true inside the range", working(30))
Assert.assertTrue("true at the inclusive lower bound", working(18))
Assert.assertFalse("false above the range", working(70))
}
}
//sampleStart
fun working(age: Int): Boolean =
false // TODO: true when age is 18..65 inclusive
//sampleEnd Show answer Hide answer
fun working(age: Int) = age in 18..65 for, indices, and in
7. Walk the elements
Given a list names, print each name. No index.
fun main() {
val names = listOf("Ada", "Grace", "Alan")
// TODO: print each name, no index
} Show answer Hide answer
for (name in names) println(name) 8. Index and value together
Print each name in names prefixed by its index, e.g. 0: Ada.
fun main() {
val names = listOf("Ada", "Grace", "Alan")
// TODO: print "0: Ada", "1: Grace", ... with withIndex()
} Show answer Hide answer
for ((i, name) in names.withIndex()) {
println("$i: $name")
} 9. Loop over positions
Print the indices of names (0, 1, 2, …) using the list’s own index range.
fun main() {
val names = listOf("Ada", "Grace", "Alan")
// TODO: print 0, 1, 2 using names.indices
} Show answer Hide answer
for (i in names.indices) println(i) 10. Not a member
Implement unknown — true when command is not in the valid list.
import org.junit.Test
import org.junit.Assert
class Test {
@Test fun notMember() {
val valid = listOf("go", "stop", "wait")
Assert.assertTrue("true when the command is absent", unknown("jump", valid))
Assert.assertFalse("false when the command is present", unknown("go", valid))
}
}
//sampleStart
fun unknown(command: String, valid: List<String>): Boolean =
true // TODO: true when command is NOT in valid
//sampleEnd Show answer Hide answer
fun unknown(command: String, valid: List<String>) = command !in valid 11. Break out of both loops
Given a grid of rows of cells, break out of both loops the moment you hit a cell where isMine is true.
fun main() {
data class Cell(val isMine: Boolean)
val grid = listOf(
listOf(Cell(false), Cell(false)),
listOf(Cell(false), Cell(true)),
)
// TODO: stop at the first mine, breaking out of BOTH loops
for (row in grid) {
for (cell in row) {
if (cell.isMine) println("found a mine")
}
}
} Show answer Hide answer
outer@ for (row in grid) {
for (cell in row) {
if (cell.isMine) break@outer
}
} Going deeper: the ..< operator and ranges
12. Half-open the modern way
Build the list [0, 1, 2, 3] for n = 4 using the modern half-open range operator, not until.
import org.junit.Test
import org.junit.Assert
class Test {
@Test fun upTo() {
Assert.assertEquals(listOf(0, 1, 2, 3), upTo(4))
Assert.assertEquals(emptyList<Int>(), upTo(0))
}
}
//sampleStart
fun upTo(n: Int): List<Int> =
emptyList() // TODO: 0 up to but not including n, using ..<
//sampleEnd Show answer Hide answer
fun upTo(n: Int): List<Int> = (0..<n).toList()0..<n is the preferred spelling of the old 0 until n — both are an IntRange, and the for/range form compiles to a plain counting loop.
13. Membership beats comparisons
Rewrite a “between” check as a single range in test: inWorkingAge(age) is true for 18 through 65 inclusive.
import org.junit.Test
import org.junit.Assert
class Test {
@Test fun working() {
Assert.assertTrue(inWorkingAge(18))
Assert.assertTrue(inWorkingAge(65))
Assert.assertFalse(inWorkingAge(17))
Assert.assertFalse(inWorkingAge(66))
}
}
//sampleStart
fun inWorkingAge(age: Int): Boolean =
false // TODO: 18..65 inclusive, using the in operator
//sampleEnd Show answer Hide answer
fun inWorkingAge(age: Int) = age in 18..65age in 18..65 compiles to the two comparisons you’d write by hand, so it’s free — and reads far better.
14. Loops aren’t expressions
Why doesn’t val x = for (i in 1..3) i compile? Reveal to check.
Show answer Hide answer
for and while are statements, not expressions — they do work but don’t produce a value, so there’s nothing to assign. To turn iteration into a result, use a collection function (map, sumOf, first), which are expressions. Only if and when return values among the control-flow constructs.
Back to the lesson, Kotlin’s if Returns a Value, or on to the next one: when.
Comments