Learning Kotlin: The For Loop

Submitted by Robert MacLean on Wed, 08/15/2018 - 09:00

More Information

  • This is the 20th post in a multipart series.
    If you want to read more, see our series index

Kotlin has two loops, while and for. When I started I was like, "yup, I know those..." - except I didn't. while works the way I expected it would but for it is something else.

First Kotlin does not have a traditional for loop, eg for (var i =0;i< max; i++)... the for loop in Kotlin is closer to the iterator foreach loop in C#.

Basic

Let's start with the basics, how do I run a loop, say 10 times where we print out 0, 1, 2, 3, 4, 5, 6, 7, 8, 9:

  1. fun main(args:Array<String>) {
  2.     for(i in 0..9) {
  3.         println(i)
  4.     }
  5. }

In this, we use a ClosedRange (0..9) to state the start and end of the loop. This would be the same as for (var i=0; i< 10; i++).

Now, normally we want to loop over an array of items, so we can do this in two ways. First the equivalent of the C# for iterator/JS for of:

  1. fun main(args:Array<String>) {
  2.     val a = arrayOf("The","Quick","Brown","Fox")
  3.     for(i in a) {
  4.         println(i)
  5.     }
  6. }

and if we do the older style of using a normal for loop and using the index we have:

  1. fun main(args:Array<String>) {
  2.     val a = arrayOf("The","Quick","Brown","Fox")
  3.     for(i in 0 until a.size) {
  4.         val value = a[i]
  5.         println(value)
  6.     }
  7. }

What is awesome in the above is the Range, rather than having the inclusive lower and inclusive upper bounds of the .. range we using the keyword until which gives us an exclusive upper bound.

Kotlin is all about helpers, and last time we looked at destructuring so it shouldn't be a surprise we can use that to have BOTH the index and the value in the for loop.

  1. fun main(args:Array<String>) {
  2.     val a = arrayOf("The","Quick","Brown","Fox")
  3.     for((i, value) in a.withIndex()) {
  4.         println("$i is $value")
  5.     }
  6. }

Extras

The for loop has two additional options worth knowing; the first is downTo which loops from largest to smallest. This example which print 4321):

  1. for (i in 4 downTo 1) print(i)

The second is step which allows you to control how many steps to take when moving to the next item, for this example we will get 42:

  1. for (i in 4 downTo 1 step 2) print(i)

Operator

Adding support for this to our own classes is trivial, we merely need to add the interface Iterator<T> to our class. This adds two methods, fun next():T which should return the next value in the collection and fun hasNext():Boolean which should return true if there is another value available. Let us look at doing this with a class of prime numbers but for our example, we will add one condition since there are infinite primes we will have a top bound so it eventually ends - this is stored in the maxToHunt variable.

In the code our next function not only returns the next value, it calculates the NEXT NEXT value too which lets us set if there are more primes left if next is called again.

  1. class PrimeNumbers : Iterator<Int> {
  2.     var currentPrime = 1;
  3.     val maxToHunt = 100;
  4.     var morePrimesToFind = true;
  5.  
  6.     override fun next():Int {
  7.         val result = this.currentPrime;
  8.  
  9.         this.currentPrime += 1;
  10.         while(this.currentPrime < this.maxToHunt) {
  11.             var primeFound = true
  12.             for(divisor in this.currentPrime-1 downTo 2) {  
  13.                 if (this.currentPrime % divisor == 0) {
  14.                     this.currentPrime += 1
  15.                     primeFound = false
  16.                     break
  17.                 }
  18.             }
  19.  
  20.             if (primeFound) {
  21.                 break
  22.             }
  23.         }
  24.  
  25.         this.morePrimesToFind = this.currentPrime < this.maxToHunt
  26.         return result
  27.     }
  28.  
  29.     override fun hasNext() = this.morePrimesToFind
  30. }
  31.  
  32. fun main(args:Array<String>) {
  33.     for (i in PrimeNumbers()) {
  34.         println("$i is prime")
  35.     }
  36. }