Thursday 27 October 2016

clojure - How to cycle a list infinitely and lazily in Kotlin?




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)
}



  1. However, this would be so much simpler and easier to read if I could take the 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")



  1. Another thing that would help is if I could look up in a list using a negative index, like in Ruby or Python:







Question:




  • Can I do cycle through a list/collection in Kotlin?

  • Is there an idiomatic way to do a negative-index-lookup in Kotlin?


Answer



Here's cycle:




fun  cycle(vararg xs: T): Sequence {
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.


No comments:

Post a Comment

c++ - Does curly brackets matter for empty constructor?

Those brackets declare an empty, inline constructor. In that case, with them, the constructor does exist, it merely does nothing more than t...