I have a list of directions
and want to find the next direction when I take a right or left turn. Here is the working code I have:
enum class Turn { R, L }
enum class Direction { N, E, S, W }
val directionsInRightTurnOrder = listOf(Direction.N, Direction.E, Direction.S, Direction.W)
private fun calculateNextHeading(heading: Direction, turn: Turn): Direction {
val currentIndex = directionsInRightTurnOrder.indexOf(heading)
var nextIndex = currentIndex + if (turn == Turn.R) 1 else -1
if (nextIndex >= directionsInRightTurnOrder.size)
nextIndex = directionsInRightTurnOrder.size - nextIndex
if (nextIndex < 0)
nextIndex += directionsInRightTurnOrder.size
return directionsInRightTurnOrder.get(nextIndex)
}
directionsInRightTurnOrder
list and cycle through it infinitely (and lazily). In Clojure, I can do that, using clojure.core/cycle:(take 5 (cycle ["a" "b"]))
# ("a" "b" "a" "b" "a")
Another thing that would help is if I could look up in a list using a negative index, like in Ruby or Python:
cycle
through a list/collection in Kotlin?Here's cycle
:
fun <T : Any> cycle(vararg xs: T): Sequence<T> {
var i = 0
return generateSequence { xs[i++ % xs.size] }
}
cycle("a", "b").take(5).toList() // ["a", "b", "a", "b", "a"]
Here's how you could implement turn application:
enum class Turn(val step: Int) { L(-1), R(1) }
enum class Direction {
N, E, S, W;
fun turned(turn: Turn): Direction {
val mod: (Int, Int) -> Int = { n, d -> ((n % d) + d) % d }
return values()[mod(values().indexOf(this) + turn.step, values().size)]
}
}
Sounds like modulo
is what you're looking for -- negative index wrap-around. Couldn't find it in Kotlin's stdlib so I brought my own.
Direction.N
.turned(Turn.R) // E
.turned(Turn.R) // S
.turned(Turn.R) // W
.turned(Turn.R) // N
.turned(Turn.L) // W
Enum#values()
and Enum#valueOf(_)
are what let you access an enum's members programmatically.
Custom sequence, which repeats indefinitely the given sequence or list can be written quite easily in terms of flatten
:
fun <T> Sequence<T>.repeatIndefinitely(): Sequence<T> =
generateSequence(this) { this }.flatten()
fun <T> List<T>.repeatIndefinitely(): Sequence<T> =
this.asSequence().repeatIndefinitely()
You can cycle through a list/collection in Kotlin by generating a sequence that returns the list/collection repeatedly and then flattening it. e.g.:
generateSequence { listOf("a", "b") }.flatten().take(5).toList()
// [a, b, a, b, a]
You can define your own modulo function for coercing both negative and positive numbers to valid indices to access elements in a list (see also Google Guava's IntMath.mod(int, int)
):
infix fun Int.modulo(modulus: Int): Int {
if (modulus <= 0) throw ArithmeticException("modulus $modulus must be > 0")
val remainder = this % modulus
return if (remainder >= 0) remainder else remainder + modulus
}
val list = listOf("a", "b", "c", "d")
list[-1 modulo list.size] // last element
list[-2 modulo list.size] // second to last element
list[+9 modulo list.size] // second element
list[-12 modulo list.size] // first element
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With