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
Другие вопросы по тегам