Looping & Ranges
The
forkeyword executes a block of code for each value in a sequence.
The set of values can be a range of integers, a String, or, as you’ll see later
in the book, a collection of items. The in keyword indicates that you are
stepping through values:
for (v in values) {
// Do something with v
}
Each time through the loop, v is given the next element in values.
Here’s a for loop repeating an action a fixed number of times:
// LoopingAndRanges/RepeatThreeTimes.kt
fun main() {
for (i in 1..3) {
println("Hey $i!")
}
}
/* Output:
Hey 1!
Hey 2!
Hey 3!
*/
The output shows the index i receiving each value in the range from 1 to 3.
A range is an interval of values defined by a pair of endpoints. There are two basic ways to define ranges:
// LoopingAndRanges/DefiningRanges.kt
fun main() {
val range1 = 1..10 // [1]
val range2 = 0 until 10 // [2]
println(range1)
println(range2)
}
/* Output:
1..10
0..9
*/
-
[1] Using
..syntax includes both bounds in the resulting range. -
[2]
untilexcludes the end. The output shows that10is not part of the range.
Displaying a range produces a readable format.
This sums the numbers from 10 to 100:
// LoopingAndRanges/SumUsingRange.kt
fun main() {
var sum = 0
for (n in 10..100) {
sum += n
}
println("sum = $sum")
}
/* Output:
sum = 5005
*/
You can iterate over a range in reverse order. You can also use a step value
to change the interval from the default of 1:
// LoopingAndRanges/ForWithRanges.kt
fun showRange(r: IntProgression) {
for (i in r) {
print("$i ")
}
print(" // $r")
println()
}
fun main() {
showRange(1..5)
showRange(0 until 5)
showRange(5 downTo 1) // [1]
showRange(0..9 step 2) // [2]
showRange(0 until 10 step 3) // [3]
showRange(9 downTo 2 step 3)
}
/* Output:
1 2 3 4 5 // 1..5
0 1 2 3 4 // 0..4
5 4 3 2 1 // 5 downTo 1 step 1
0 2 4 6 8 // 0..8 step 2
0 3 6 9 // 0..9 step 3
9 6 3 // 9 downTo 3 step 3
*/
-
[1]
downToproduces a decreasing range. -
[2]
stepchanges the interval. Here, the range steps by a value of two instead of one. -
[3]
untilcan also be used withstep. Notice how this affects the output.
In each case the sequence of numbers form an arithmetic progression.
showRange() accepts an IntProgression parameter, which is a built-in type
that includes Int ranges. Notice that the String representation of each
IntProgression as it appears in output comment for each line is often
different from the range passed into showRange()—the IntProgression is
translating the input into an equivalent common form.
You can also produce a range of characters. This for iterates from a to z:
// LoopingAndRanges/ForWithCharRange.kt
fun main() {
for (c in 'a'..'z') {
print(c)
}
}
/* Output:
abcdefghijklmnopqrstuvwxyz
*/
You can iterate over a range of elements that are whole quantities, like integers and characters, but not floating-point values.
Square brackets access characters by index. Because we start counting
characters in a String at zero, s[0] selects the first character of the
String s. Selecting s.lastIndex produces the final index number:
// LoopingAndRanges/IndexIntoString.kt
fun main() {
val s = "abc"
for (i in 0..s.lastIndex) {
print(s[i] + 1)
}
}
/* Output:
bcd
*/
Sometimes people describe s[0] as “the zeroth character.”
Characters are stored as numbers corresponding to their Unicode values, so adding an integer to a character produces a new character corresponding to the new code value:
// LoopingAndRanges/AddingIntToChar.kt
fun main() {
val ch: Char = 'a'
println(ch + 25)
println(ch < 'z')
}
/* Output:
z
true
*/
The second println() shows that you can compare character codes.
A for loop can iterate over Strings directly:
// LoopingAndRanges/IterateOverString.kt
fun main() {
for (ch in "Jnskhm ") {
print(ch + 1)
}
}
/* Output:
Kotlin!
*/
ch receives each character in turn.
In the following example, the function hasChar() iterates over the String s
and tests whether it contains a given character ch. The return in the
middle of the function stops the function when the answer is found:
// LoopingAndRanges/HasChar.kt
fun hasChar(s: String, ch: Char): Boolean {
for (c in s) {
if (c == ch) return true
}
return false
}
fun main() {
println(hasChar("kotlin", 't'))
println(hasChar("kotlin", 'a'))
}
/* Output:
true
false
*/
The next atom shows that hasChar() is unnecessary—you can use built-in
syntax instead.
If you simply want to repeat an action a fixed number of times, you may use
repeat() instead of a for loop:
// LoopingAndRanges/RepeatHi.kt
fun main() {
repeat(2) {
println("hi!")
}
}
/* Output:
hi!
hi!
*/
repeat() is a standard library function, not a keyword. You’ll see how it was
created much later in the book.
Exercises and solutions can be found at www.AtomicKotlin.com.