How to cycle a list infinitely and lazily in Kotlin?
我有一张
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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 2 | (take 5 (cycle ["a""b"])) # ("a""b""a""b""a") |
另一件有用的事情是,如果我可以使用负索引在列表中查找,比如在Ruby或Python中:
- http://rubyquicktips.com/post/996814716/use-negative-array-indexs
- python列表的负索引
问题:
- 我可以通过Kotlin的列表/集合来完成
cycle 吗? - 在Kotlin中有没有一种惯用的负索引查找方法?
这里是
1 2 3 4 5 6 | 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"] |
这里是你如何实现转换应用的:
1 2 3 4 5 6 7 8 9 10 | 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)] } } |
听起来像是EDOCX1&13..你在看什么--负指数WRAP-周围。我不能在Kotlin's stdlib找到它所以我自己买
1 2 3 4 5 6 | Direction.N .turned(Turn.R) // E .turned(Turn.R) // S .turned(Turn.R) // W .turned(Turn.R) // N .turned(Turn.L) // W |
你是怎么让ENUM成员的方案编制人员进入的?
你可以循环通过一个列表/收藏在科特兰,通过生成一个顺序,返回列表/收藏,然后拍摄它。E.G.:
1 2 | generateSequence { listOf("a","b") }.flatten().take(5).toList() // [a, b, a, b, a] |
你可以确定自己的模块函数,以强化消极和正数值,从而有效地指数访问元素的列表(另见Google Guava's EDOCX1&11):
1 2 3 4 5 6 7 8 9 10 11 | 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 |
Custom sequence,which repeats indefinitely the given sequence or list can be written quite easily in terms of
1 2 3 4 5 | fun <T> Sequence<T>.repeatIndefinitely(): Sequence<T> = generateSequence(this) { this }.flatten() fun <T> List<T>.repeatIndefinitely(): Sequence<T> = this.asSequence().repeatIndefinitely() |
Paraphrasing the discussion on Kotlin Slack:
-
由于负面指数仍然需要处理,这将是一个简单的过程,而不是像EDOCX1那样优雅的过程。
-
实施自行车列表的一个选择是一个
Sequence 。然而,需要用generateSequence 写作或生成。我们认为这是一种过度杀戮。
也许我会跟
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | enum class Direction { N, E, S, W; private val order by lazy { listOf(N, E, S, W) } fun add(turns: Int): Direction { val currentIndex = order.indexOf(this) var nextIndex = (currentIndex + turns) % order.size return order.possiblyNegativeLookup(nextIndex) } fun subtract(turns: Int) = add(-1 * turns) fun next(): Direction = add(1) fun previous(): Direction = subtract(1) } |
ZZU1
因此,最终的守则转向:
1 | val nextHeading = if (move.turn == Turn.R) heading.next() else heading.previous() |