you can't reassign loop variables?? I have a neste...
# getting-started
r
you can't reassign loop variables?? I have a nested range loop i and j. when j is finished, I sometimes need to reset i to be j, to avoid covering old ground. super common thing you have to do in leetcode algorithms, and works in java.
j
What's a loop variable?
j
Could you please show an example? Usually in Kotlin you don't need to manipulate loop variable at such a low level, we use higher order functions on collections instead
j
I assume what ever you're trying to do can be resolved by declaring your variable outside the loop
Luckily kotlin has scope functions, that can reduce the scope of that outer variable.
r
no this is a tokenizer for on-demand lexical analysis
I need fine grain control of the exact index of text I am looking at at any given moment
as I loop through a string, searching for keywords
j
If you have a special case where you actually need to make the "loop variable" jump here and there, then I guess you'd better declare the variable yourself, and control it entirely.
for
is just a higher-level convenience, but you can simply use a local variable and a while loop if you have uncommon needs
r
Copy code
fun findConsecutiveXs(string: String): Int {
    var count = 0
    for (i in 0..string.length) {
        if (string[i] == 'x') {
            for (j in i + 1..string.length) {
                if (string[j] == 'x') {
                    count += 1
                } else {
                    i = j + i; break
                }
            }
        }
    }
}
here is an example of when you might want to be able to manually move
i
so you dont retread old ground
j
Yup if you're not iterating by manually calling I++ you'll lose some control
k
In Java, a
for
loop is just a glorified
while
loop. It has a starting value, a condition and a statement that is executed at the end of each iteration. In Kotlin, if that's what you want to do, you do it with a
while
loop. On the other hand, Kotlin
for
loops are actually more like Java enhanced for loops ("foreach loops").
for (i in 1..n)
is conceptually similar to
for (element in collection)
. In both cases,
i
iterates through elements of an Iterable - be it an IntRange or a List. That's why it doesn't make sense to reassign
i
to some arbitrary value.
r
i see
in that example code, the important thing is being able to make
i
jump ahead by an arbitrary amount
If I just continue, that only does i+1
but if I had ran the j loop 7 times, then i needs to
continue
7 times in a row
so while loop i guess.
1
j
What's the goal of your function? Is it to count the number of Xs that follow an X in the string? If yes, then we can do simpler without a nested for loop or any index at all, by just using a boolean to keep track of the state.
Copy code
fun findConsecutiveXs(string: String): Int {
    var seenX = false
    var count = 0
    for (c in string) {
        if (c == 'x') {
            if (seenX) {
                count++
            } else {
                seenX = true
            }
        } else {
            seenX = false
        }
    }
    return count
}
Or... you could just use Kotlin's niceties and avoid the loops altogether:
Copy code
fun countConsecutiveXs(string: String): Int =
    string.zipWithNext().count { (c1, c2) -> c1 == 'x' && c2 == 'x'}
Most of the time, in Kotlin, you can express the intent better by actually doing the things you would describe. If the problem statement is "count Xs that follow another X", then the code of the last function is much closer to the problem statement than the loops.
4
k
The problem is in the mental translation from "count the lengths of consecutive Xs" to "count Xs that follow another X" - it may not be immediately obvious that these two statements are equivalent.
j
I just inferred the problem statement from the initial code snippet. But yeah it would be interesting to know how it's initially formulated