关于Clojure:如何在Kotlin中无限而懒散地循环列表?

How to cycle a list infinitely and lazily in Kotlin?

我有一张directions的清单,想在我右转或左转时找到下一个方向。以下是我的工作代码:

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)
}
  • 然而,如果我能拿着directionsInRightTurnOrder列表无限地(和懒惰地)循环使用它,这将是如此简单和容易阅读。在Clojure中,我可以使用clojure.core/cycle来实现这一点:
  • 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 flatten

    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写作或生成。我们认为这是一种过度杀戮。

    也许我会跟

  • DirectionAware of nextand previous
  • 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)
    }
  • ListpossiblyNegativeLookup
  • ZZU1

    因此,最终的守则转向:

    1
    val nextHeading = if (move.turn == Turn.R) heading.next() else heading.previous()