preface

It has been a few months since I started Kotlin in April this year. In Kotlin, loop is a feature of this language. Recently, I used Canvas to do game development on Android, and I wrote a lot of loops, but I found it difficult to write multivariable For loop. I ended up either writing Kotlin calls in Java, or writing While loops. Today, I solved this pain point, so I decided to write an article about it.

The basic use

Let’s start with the simplest For loop before we get down to it

Loop from 0 to 100

Until the keyword

The until keyword requires a value on both the left and right side, and the until loop is a closed left open right interval

for (i in 0 until 100) {
    println(i) // Output: 0 ~ 99
}
Copy the code

The final output contains 0 but not 100

Use..

. It also has a meaning in Kotlin. It’s called an interval expression, and it represents a left and right interval. Like the until keyword, both sides need a value when used

for (i in 0.100.) {
    println(i) // Output: 0 ~ 100
}
Copy the code

The final output contains both 0 and 100

supplement

In fact.. The keyword can also be directly declared as a variable, which represents an interval. The variable will loop over the interval stored in it as it loops through

val test = 0.100.
Copy the code

Note: Use.. The created range must be in ascending order, that is, from small to large, not from large to small. You need to use another keyword “downTo” if you want to create a range from large to small

Loop from 100 to 0

DownTo keyword

Kotlin’s descending loop uses the keyword downTo, which also requires a value for both the left and right sides

for (i in 100 downTo 0) {
    println(i) // Output: 100 ~ 0
}
Copy the code

You will suddenly realize why it is 100 ~ 0 and not 100 ~ 1. At the end of the keyword. The downTo keyword generates a left-closed and right-closed interval in terms of descending loops

Step keyword

Kotlin defaults to a step size of 1 for the loop. To change the step size, use the step keyword

Loop from 0 to 10 and set the step size to 2

for (i in 0.10. step 2) {
    print("${if (i == 10) i else "$i-"}") // Output: 0--2--4--6--8--10
}
Copy the code

Looping array or list

So this is all about how you loop from one number to another, and a lot of times you loop by getting the values in a container like an ArrayList. The operation of looping these containers is simple in Kotlin

Loop through an array or list

For reasons of length, I will not post the code results here. Experts can try the following code by themselves

Define an array

val arrayList = arrayListOf(1.2.3.4.5.6.12.31.23.123.12.3.123.2)
Copy the code

Get the element out

for (i in arrayList) {
    println(i) // output: 1,2,3,4.... 2
}
Copy the code

Loop through the index and elements

Fetching the element’s index at the same time requires calling the container’s withIndex() method during the loop

for ((index, item) in arrayList.withIndex()) {
    println("index: $index, item: $item") // Output: index: 0, item: 1.... index: 13, item: 2
}
Copy the code

Iterate over an array or list by index

There are some cases where you can write it this way by traversing the index

for (i in 0 until arrayList.size) {
    println(arrayList[i]) // output: 1,2,3,4.... 2
}
Copy the code

At this point you will find that your Idea will give you a yellow line warning because Kotlin’s case already provides you with an extension method indices

for (i in arrayList.indices) {
    println(arrayList[i]) // output: 1,2,3,4.... 2
}
Copy the code

A little note

Kotlin’s for loop is actually much more than iterating through arrays or lists. It’s possible to iterate over any data container used in basic daily development (as long as the container implements the Iterable interface)

Multivariable cycle

Remember the pain point I mentioned in the introduction, which is the multivariable loop. Converting a multivariable for loop in Java to Kotlin directly translates to the syntax of while, but while leads to an explosion of lines of code, poor readability, and the creation of local variables.

Into each other

Take a look at the code for a Java multivariable for loop

// Java before conversion
for (int i = 0, j = 100; i < 100 && j > 0; i++, j--) {
    System.out.println("i: " + i + ", j: " + j); I: 0, j: 100 ~ I: 99, j: 1
}
Copy the code

If you were to change this code to Kotlin’s for loop, what would you do? Not so fast, let’s turn into Kotlin and see what happens

// After conversion kotlin
var i = 0
var j = 100
while (i < 100 && j > 0) {
    println("i: $i, j: $j") I: 0, j: 100 ~ I: 99, j: 1
    i++
    j--
}
Copy the code

Here Kotlin directly converts to while for us, and the downside of that has already been said, so I don’t need to go over it. Go straight to Kotlin for’s code

for ((i, j) in (0 until 100).zip(100 downTo 0)) {
    println("i: $i, j: $j") I: 0, j: 100 ~ I: 99, j: 1
}
Copy the code

You will notice that the output of all three loops is the same. For reasons of length, we will introduce the Kotlin multivariable loop

Defining multivariable

In Kotlin’s for, the in keyword is usually used to define a loop variable, or to indicate the index or each element of the loop container. The loop container is not considered here, only the variable that defines the loop. When multiple variables need to be defined inside (), each variable is separated by a comma. After the in keyword, you set the loop

for((i,j)  in...). {}Copy the code

Set loop interval

If you haven’t noticed, kotlin’s for loop defines a variable without giving it an initial value. Instead, it specifies the interval in which it needs to loop and whether it is a descending or a positive loop, so the in loop described above starts with a defined variable rather than an initial value

Now set the loop ranges for the above defined loop variables. Multiple loop ranges are set using the.zip() function

for ((i, j) in (0 until 10).zip(1 until 10)) {
    println("i: $i, j: $j")}Copy the code

The above code means that the range of I is in ascending order from 0 to 10, and the range of j is in ascending order from 1 to 10

So let’s print out the result

Right? Shouldn’t I be 0 to 9? Why does it end at 8? Don’t worry, let’s look at j’s cycle interval from 1 to 10, okayUntil left closed right openWe have one fewer j cycles than I cycles, so we’re done. You might be confused, why is it over shouldn’t I output to 9, don’t worry, we’re writing the same code in Java

for (int i = 0, j = 1; i < 10 && j < 10; i++, j++) {
    System.out.println("i:" + i + ", j:" + j);
}
Copy the code

The output is consistent, and the code should make sense with Java

Let’s continue to

Three variables and four variables

Sometimes there are three or four variables in the loop and you don’t know where to start. Try zip().zip() and you’ll get an error

for((i,j,k) in (0.100.).zip(0.100.).zip(0.100.)) {}// Error code
Copy the code

Kotlin: Destructuring declaration initializer of type Pair<Pair<Int, Int>, Int> must have a ‘component3()’ function

So you can’t say, three variables or four variables or more, you need to use a Pair as a loop variable, Pair is a binary tuple, you can assign multiple values to one variable at the same time, you can assign multiple values to multiple variables at the same time, there’s a binary tuple, Triple, However, I did not use three points in the learning process, it seems that the current for loop only supports binary tuples (zip() returns binary tuples). If there is anything wrong, welcome to know the details of the big man to correct, I will also modify this article at the first time

All right, let’s get started

Three variables

Very little has changed. In is still preceded by two variables, but one of them stores a tuple with values inside

On the first code
for ((i, jPair) in (1.100.).zip((0.100.).zip(0.100.)) ) {
    println("i: $i.$jPair")}Copy the code

You will find that calling two zip functions, as if we haven’t introduced the functions of the zip function, will cross the bridge when it comes to the output

And you’ll notice that at the end of the output, jPair becomes an object, and at this point, jPair is a tuple object, and the output object has two values in it, and we just output something like this, what if we want to get one of those values? So write

for ((i, jPair) in (1.100.).zip((0.100.).zip(0.100.))) {
    println("i: $i |  jPair.firstValue: ${jPair.first} |  jPair.secondValue: ${jPair.second}")}Copy the code

Output result:A binary tuple can store only two values, both of which can passObject.first and object.secondNow let’s go back to zip.

Zip () is introduced

Returns a list of pairs built from the elements of this collection and other collection with the same index. The returned list has length of the shortest collection.

Zip () returns the set with the smallest index as the index, and takes the intersection of the two sets.

If you’re confused, I am too. Let’s skip the comments and look at the parameters that the source code receives and returns

public infix fun <T, R>可迭代<T>.zip(other: 可迭代<R>): List<Pair<T, R>> {
    return zip(other) { t1, t2 -> t1 to t2 }
}
Copy the code

The received parameter needs to be a type that implements the Iterable interface. Kotlin’s commonly used data storage structures actually implement this interface, and our interval expressions also support this interface.

After looking at the return value, which returns a list of tuple objects, you can look at the three-variable for loop and see if it’s self-explanatory

Four variables

So let me write the four variables, and I won’t go into the details, but it’s just a little bit different from the three variables

for ((iPair, jPair) in ((1.100.).zip(1.100.)).zip((0.100.).zip(0.100.))) {
    println("iPair: $iPair |  jPair: $jPair")}Copy the code

Execution Result:

To fetch the value of a tuple object, as I mentioned above, I won’t repeat it here.

summary

In general, Kotlin is quite complex when it comes to multivariable loops, but if you are familiar with the syntax, it can look very concise, but it is rarely used in daily development, just to mention that Kotlin can only do so much. If you don’t write your own examples, you’ll get a better idea of how the zip() function works and how the for loop executes the flow when it’s multivariable

Cycle control

Sometimes we need some control over the loop, and Kotlin is unique in this regard

Structural jump expression

Like most languages, Kotlin’s for loop has two structured jump expressions:

  • Break: Terminates the closest loop
  • Continue: Jumps out of the most recent loop
for (i in 0 until 10) {
    if (i == 5) break // Output: 0 ~ 4
}

for (i in 0 until 10) {
    if (i == 5) continue // Output: 0 ~ 9
}
Copy the code

Tag name

Tag naming is one of the most interesting things about Kotlin loops. We can assign a tag to a loop and then use a structural jump expression to manipulate the tag for the loop.

Name format: label name @

To break out of a specified tag, write: break@ tag name or continue@ tag name

all@ for (i in 0 until 100) {
    inner@ for (j in 100 downTo 0) {
        if (i == 60) break@inner
        if (j == 60) continue@all
        println("j: $j")
    }
    println("i: $i")}Copy the code

You can try it yourself, and the results will not be posted here

conclusion

Kotlin’s For loop is fairly well summarized, from simple use to multivariable, traversing common containers, and loop control. This is my first article. Some of the points may not be well described, but I believe that if you try with the code, you will soon understand what I want to express. Finally, thank you for reading!