Kotlin Prepend элемент
Я ищу альтернативу Kotlin:(cons 1 '(2 3))
в шутку или1 : [2, 3]
в хаскеле или1 :: List(2, 3)
в скале,
(которые все в результате чего-то вроде [1, 2, 3])
так что я могу добавить элемент к List<T>
(или любой другой список, который вы можете предложить).
Также будет хорошо, если кто-то может предоставить O(1) head
а также tail
Kotlin альтернативы (я нашел только first()
)
8 ответов
Любой класс, который реализует Deque
подойдет для вас, например LinkedList
:
val linkedList = LinkedList(listOf(2, 3))
linkedList.push(1)
println(linkedList) // [1, 2, 3]
Создание списков через конструктор LinkedList(listOf(2, 3))
во многих местах это может раздражать, поэтому смело пишите фабричный метод:
fun <T> linkedListOf(vararg elements: T): LinkedList<T> {
return LinkedList<T>(elements.toList())
}
// Usage:
val list = linkedListOf(2, 3)
list.push(1)
println(list) // [1, 2, 3]
Я думаю, что проще всего было бы написать:
var list = listOf(2,3)
println(list) // [2, 3]
list = listOf(1) + list
println(list) // [1, 2, 3]
Там нет конкретного tail
реализации, но вы можете вызвать.drop(1), чтобы получить то же самое. Вы можете сделать это head\tail
более общий, написав эти свойства расширения:
val <T> List<T>.tail: List<T>
get() = drop(1)
val <T> List<T>.head: T
get() = first()
Затем:
val list = listOf(1, 2, 3)
val head = list.head
val tail = list.tail
Немного больше информации: функция хвоста Kotlin List
Просто, просто оберните элемент, чтобы добавить в List
а затем использовать +
оператор (или List.plus()
) соединить два Lists
:
val list1 = listOf(2, 3) // [2, 3]
val list2 = listOf(1) + list1 // [1, 2, 3]
Для вашего второго вопроса, в Kotlin 1.2 есть:
List.first()
List.last()
Оба O(1)
Это можно легко сделать с помощью функций расширения, как показано ниже
Предварительный элемент
fun <T> MutableList<T>.prepend(element: T) {
add(0, element)
}
Предварительный список
fun <T> MutableList<T>.prependAll(elements: List<T>) {
addAll(0, elements)
}
Вставляет элемент в список по указанному индексу.
abstract fun add(index: Int, element: E)
Таким образом, ответ
list.add(0,element)
Если вы по какой-то причине часто делаете это в своем коде, рассмотрите возможность добавления метода оператора расширения, такого как:
operator fun <T> T.plus(tail: List<T>): List<T> {
val list = ArrayList<T>(1 + tail.size)
list.add(this)
list.addAll(tail)
return list
}
Тогда ваш код может работать как Scala-подобный: 1 + listOf(2, 3)
Другой способ добиться того же поведения, короче, но жертвует памятью:
operator fun <T> T.plus(tail: List<T>): List<T> {
return mutableListOf(this).apply {
addAll(tail)
}
}
Чтобы быть как можно ближе к Лиспу, подумайте об использовании неизменяемого связанного списка.
Вы можете использовать pcollections
val list = ConsPStack.from(listOf(2, 3))
val newList = list + 1
println(list) // [2, 3]
println(newList) // [1, 2, 3]
Голова:
list.first() // 1
list[0] // 1
(к сожалению, эта вещь требует одного распределения)
Хвост:
list - 0 // [2, 3]
list.subList(1) // [2, 3]
Выглядит довольно некрасиво
Надеемся, что мы получим лучший API, когда https://github.com/Kotlin/kotlinx.collections.immutable будет готов. Это попытка создать стандартные неизменяемые коллекции Kotlin (а не только те, которые доступны только для чтения). На данный момент этот проект все еще находится на очень ранней стадии (я не смог найти структуру, которая бы поддерживала эффективный prepend/head/tail)
Я не совсем уверен, что вы хотите сделать, поэтому, пожалуйста, попробуйте один из следующих.
Список мутаций:
val list = mutableListOf(3, 2)
list.add(1)
Составление неизменного списка:
var list = listOf(3, 2)
list = list + 1