28

How can I modify the loop variable in Kotlin?

For my particular case, I have a for-loop in which, for certain conditions, I want to skip the next iteration:

for(i in 0..n) {
  // ...
  if(someCond) {
    i++ // Skip the next iteration
  }
}

However, when I try this, I'm told that "val cannot be reassigned".

0

3 Answers 3

45

You can't mutate the current element, you would need to use a while loop instead:

var i = 0
while (i <= n) {
    // do something        
    
    if (someCond) {
        i++ // Skip the next iteration
    }

    i++
}

What are you trying to do? There is a chance there is a more idiomatic way to do this.

If you could restructure this logic to skip the current iteration, why not use continue:

for (i in 0..n) {
    if (someCond) {
        continue
    }
    // ...
}

Side note: .. ranges are inclusive, so to loop through e.g. a list of size n you usually need 0..(n - 1) which is more simply done with until: 0 until n.


In your specific case, you can use windowed (Kotlin 1.2):

list.asSequence().filter { someCond }.windowed(2, 1, false).forEach { 
    val (first, second) = it
    // ...
}

asSequence will convert the list into a Sequence, removing the overhead of filter and windowed creating a new List (as they will now both return Sequences).

If you want the next pair to not include the last element of the previous pair, use windowed(2, 2, false) instead.

Sign up to request clarification or add additional context in comments.

4 Comments

The task at hand involves iterating through adjacent pairs of elements...so the loop works with indices i and i+1 together. The condition happens if I discover something about i+1 that means it shouldn't be looked at anymore.
I might suggest that your while loop could be a little more succinct by initializing i to -1 and making the condition (++i <= n). This would also ensure no branch accidentally forgets to increment.
Not exactly. Doing that would loop through the pairs, (0,1), (2,3), etc., but it would never work with the pair (1,2).
I must say, they made this unnecessarily complicated. Imo one of the few areas where Kotlin has rather regressed than evolved.
1

It looks like what you're really trying to do is iterate a sliding window of size 2 over a list. If you're using kotlin 1.2 or later, you might use the List.windowed() library function.

For example, to consider each pair of adjacent elements, but discarding the ones where the second of the pair is negative, you would do:

val list = listOf(1, 2, 3, -4, -5, 6)
list.windowed(2,1).filter { it[1] > 0 }.apply(::println)

Which would print out

[[1, 2], [2, 3], [-5, 6]]

having skipped the pairs [3, -4] and [-4, -5]

Comments

-2

while many people described the problem and suggested a solution with advanced methods or operators which I think is not suitable for beginners. I applied a fix on the code so that you can understand it easily and it just uses a while loop instead of for loop.if you could understand it and found it useful please consider accepting the answer

fun main(args:Array<String>){

    var alphabet = mutableListOf(
            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'
    )
    var key = "keyword"
    println(key)
    for (i in key.indices)
    {
        var j = 0
        while (j < alphabet.size) {
            if (key[i] == alphabet[j]){
                alphabet.removeAt(j)     // 1. this line have error
            } else j++
        }
    }
    print(alphabet)
}

1 Comment

The top answer starts with a while loop -- one that is simpler and clearer than yours.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.