David Callanan
David Callanan

Reputation: 5958

How to make a traditional for-loop in Kotlin

JavaScript

for (var x = 0; x < 360; x += 0.5)
{
  // ...
}

How do I do this in Kotlin?


Note that my step size is a floating point and so a regular range won't work:

for (x in 0.0 until 360.0 step 0.5) {
  // ...
}

I also need to exclude the ending value, hence why I'm using until.


I will resort to a while loop for now:

var x = 0.0;

while (x < 360.0) {
  // ...
  x += 0.5
}

Upvotes: 4

Views: 3033

Answers (4)

Adam
Adam

Reputation: 1009

There isn't a way to do this right now in Kotlin because Kotlin does not have "traditional" for loops. I believe you're right in choosing a while loop. In fact, traditional for loops are just while loops in disguise:

for (init; condition; post) {
    // do something
}

can always be rewritten,

init
while (condition) {
    // do something
    post
}

with no change in behavior, because the init statement will always execute and the condition will always be checked before the loop runs even once. One thing this construct can't give you is a variable that's only scoped to this block. If you're really after that behavior, the following would work, though it's not very idiomatic.

for (x in generateSequence(0.0) { it + 0.5 }.takeWhile { it < 360.0}) {
    println(x)
}

If you're using a Sequence, you might also be interested in the more idiomatic forEach:

generateSequence(0.0) { it + 0.5 }.takeWhile { it < 360.0 }.forEach { x ->
    // do something
}

Upvotes: 6

aBe
aBe

Reputation: 422

Kotlin is so flexible that one could hack a custom solution:

private infix fun (((Double) -> Unit, Double) -> Unit).step(step: Double) = 
    fun(action: (Double) -> Unit) = this(action, step)
    
private infix fun Double.upto(to: Double) =
    fun(action: (Double) -> Unit, step: Double) { 
        var v = this
        while (v < to) {
            action(v)
            v += step
        }
    }

fun main() {
    // Usage:
    (0.0 upto 360.0 step 0.5) { 
        println(it)
    }
}

What I did above is to create two infix functions.

The upto() infix function can be used with two Doubles: it takes 0.0 upto 360.0 and returns a function that expects two arguments: an action function and the step double value.

The step infix function can be used with functions returned by upto() combined with a Double (so f step 0.5). It returns a function that calls the upto() function passing the step value and the user's { ... } block that gets called for each iteration.

Short and convoluted.

A simpler alternative:

inline fun doubleFor(
  from: Double, to: Double, step: Double, action: (Double) -> Unit
) {
    var v = from
    while (v < to) {
        action(v)
        v += step
    }
}

fun main() {
    // Usage:
    doubleFor(0.0, 360.0, 0.5) { 
        println(it)
    }
}

A good IDE would show the argument names next to the values making the meaning of the arguments in the usage code obvious.

A third approach can be found at https://stackoverflow.com/a/44332139/2933899 which allows one to write for(x in 0.0 .. 360.0 step 0.5) { println(x) } with the inconvenience that the top boundary value is included.

Run these at https://pl.kotl.in/ZuR354Fas

Upvotes: 0

Harshvardhan Joshi
Harshvardhan Joshi

Reputation: 3193

I agree with Answer by @AdamYakes. Since the until operator is not available for Floating value type, you can not use it for floating step value.

However, If you still want to use

for (x in 0.0 until 360.0 step 0.5) {
  // use value
}

you can do that as following:

for (x in 0 until 3600 step 5) {
  // use (value / 10)
}

Upvotes: 3

leonardkraemer
leonardkraemer

Reputation: 6783

As repeated addition is just a shorthand for multiplication you can look at for (x in 0.0 until 360.0 step 0.5) as "do something for as many times as 0.5 fits in 360". Therefore it would make sense to express it like this:

val times = (360 / 0.5).toInt()
repeat(times){

}

of cause you can also inline times to

repeat(times = (360 / 0.5).toInt()){

}

The advantage is that you skip the sequence generation. Con -- you lose the access to your counting variable x.

see also https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/repeat.html

Upvotes: 3

Related Questions