Intereting Posts
Преобразование кода с Java в Kotlin в Android Studio EditText теряет фокус наTextChange Retrofit2 и kotlin Как создать экземпляр объекта с использованием значений параметров конструктора по умолчанию в Kotlin? Как вызвать сокращение на пустой массив Kotlin? Как исправить ошибку вывода типа в Completed, преобразованную с помощью RxLifecycle.bindToLifecycle ()? Общий код между сервером Kotlin и клиентскими проектами с использованием Gradle «Ошибка неоднозначности разрешения перегрузки» разрешена с другой перегрузкой Не удается получить доступ к внутренним компонентам из тестового источника с помощью Android Метод, который не вызывается, без ошибок, может быть, связан с дженериками / сопутствующими объектами / наследованием / параллелизмом / вложением Spring JPA не может отображать поле с пользовательским сеттером в классе данных Kotlin Java vs Kotlin generics Найти последнее вхождение массива String в массиве с помощью Kotlin Выбрать свойство из каждого объекта в списке почему не могу я иногда пропускаю интерфейс в котлин?

Как бесконечно и лениво перебирать список в Котлин?

У меня есть список directions и вы хотите найти следующее направление, когда я делаю правый или левый поворот. Вот рабочий код, который у меня есть:

 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. Тем не менее, это было бы намного проще и проще для чтения, если бы я мог взять список directionsInRightTurnOrder и бесконечно (и лениво) прокручивать его. В Clojure я могу это сделать, используя clojure.core / cycle :
 (take 5 (cycle ["a" "b"])) # ("a" "b" "a" "b" "a") 
  1. Еще одна вещь, которая могла бы помочь, – это, если бы я мог искать в списке, используя отрицательный индекс, например, в Ruby или Python:

    • http://rubyquicktips.com/post/996814716/use-negative-array-indices
    • Отрицательный индекс для списка Python

Вопрос:

  • Можно ли перебирать список / коллекцию в Котлин?
  • Есть ли идиоматический способ поиска отрицательного индекса в Котлине?

    Вот 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"] 

    Вот как вы можете реализовать приложение-приложение:

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

    Похоже, что modulo – это то, что вы ищете – отрицательный индексный обход. Не мог найти его в stdlib Котлина, поэтому я принес свою.

     Direction.N .turned(Turn.R) // E .turned(Turn.R) // S .turned(Turn.R) // W .turned(Turn.R) // N .turned(Turn.L) // W 

    Enum#values() и Enum#valueOf(_) – это то, что позволяет вам обращаться к членам enum программным образом.

    Пользовательская последовательность, которая бесконечно повторяет данную последовательность или список, может быть легко написана с точки зрения flatten :

     fun <T> Sequence<T>.repeatIndefinitely(): Sequence<T> = generateSequence(this) { this }.flatten() fun <T> List<T>.repeatIndefinitely(): Sequence<T> = this.asSequence().repeatIndefinitely() 

    Вы можете циклически перебирать список / коллекцию в Kotlin, создавая последовательность, которая повторно возвращает список / коллекцию, а затем сглаживает ее. например:

     generateSequence { listOf("a", "b") }.flatten().take(5).toList() // [a, b, a, b, a] 

    Вы можете определить свою собственную модульную функцию для принуждения как отрицательных, так и положительных чисел к действительным индексам для доступа к элементам в списке (см. Также IntMath.mod(int, int) Google Guava):

     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 

    Перефразируя дискуссию о kotlin Slack :

    • использование List#modulo сделало бы это более простым, но не таким элегантным, как cycle , так как отрицательные индексы все равно нужно будет обрабатывать.

    • Одним из вариантов реализации циклического списка является Sequence . Тем не менее, пользовательская Sequence должна быть записана или сгенерирована с использованием generateSequence . Мы думали, что это слишком тяжело для этой ситуации.

    В конце концов я пошел с:

    1. Direction указаний о next и previous :
     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) } 
    1. Расширение List с помощью possiblyNegativeLookup :
     fun <E> List<E>.possiblyNegativeLookup(i: Int): E { return if (i < 0) this[this.size + i] else this[i] } 

    Таким образом, окончательный код превращается в:

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