Подтвердить что ты не робот

Функция хвоста Котлина

Я пытаюсь найти функцию хвоста в List<T>, но я не смог найти ее. Я закончил это.

fun <T> List<T>.tail() = this.takeLast(this.size -1)

Есть ли лучший способ сделать это?

4b9b3361

Ответ 1

Kotlin не имеет встроенной функции List<T>.tail(), поэтому реализация вашей собственной функции расширения является единственным способом. Хотя ваша реализация совершенно прекрасна, ее можно немного упростить:

fun <T> List<T>.tail() = drop(1)

Или вместо функции расширения вы можете определить свойство расширения:

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

Ответ 2

Ваши решения и решения Vladimir Mironov будут работать, но они автоматически создают нетерпеливые копии исходного списка (без первого элемента), что может занять очень много времени для больших списков. Я бы определил его с помощью класса оболочки List, который делегирует свои методы обернутому, игнорируя первый элемент с помощью настроек индекса:

private class TailList<T> (private val list: List<T>) : List<T> {
    override val size: Int
        get() = list.size -1

    override fun isEmpty(): Boolean = size == 0

    override fun iterator(): Iterator<T> = listIterator()
    override fun listIterator(): ListIterator<T> = list.listIterator(1)
    override fun listIterator(index: Int): ListIterator<T> = list.listIterator(index + 1)
    override fun subList(fromIndex: Int, toIndex: Int): List<T> = list.subList(fromIndex + 1, toIndex + 1)
    override fun lastIndexOf(element: T): Int = list.lastIndexOf(element) - 1
    override operator fun get(index: Int): T = list[index + 1]

    // The following member functions require the copy of a new list
    override fun containsAll(elements: Collection<T>): Boolean = tailList.containsAll(elements)
    override fun contains(element: T): Boolean = tailList.contains(element)
    override fun indexOf(element: T): Int = tailList.indexOf(element)

    private val tailList by lazy { ArrayList(this) }  // makes a proper copy the elements this list represents
}

Вы можете заметить функции в секции после того, как комментарий по-прежнему заканчивается тем, что делает желаемую копию. Я сделал это ради простоты. Для памяти я создал свойство lazy tailList

Все они могут быть реализованы путем повторного использования коллекции вручную, а не для выполнения каких-либо делегирования. Если это то, что вы предпочтете, я уверен, вы можете понять это.

При этом свойства головы и хвоста становятся такими:

val <T> List<T>.tail: List<T> 
    get() =
        if(this.isEmpty())
            throw IllegalStateException("Cannot get the tail of an empty List")
        else
            TailList(this)

val <T> List<T>.head: T
    get() = this[0]  // or first()

Если вам это действительно нужно, я могу добавить обновление, чтобы сделать последние три функции-члена, чтобы они не делали желающих копировать.

EDIT: Примечание. Если вы следовали соглашениям, которые Котлин следовал до сих пор, вы бы не сделали хвост List ленивым, как это, так как все их функции на List делают нетерпеливые копии. Вместо этого, особенно если вы используете head и tail для рекурсивной итерации по списку, я бы посмотрел, можно ли как-нибудь попробовать эту идею обертки на Sequence. Sequence целая точка существования - для ленивой работы над коллекциями.

ИЗМЕНИТЬ 2: По-видимому sublist() создает представление и поэтому уже ленив. По сути, я только что научил вас, как создать реализацию для подписок, за исключением того, что я сузил его только до хвоста.

Итак, в этом случае просто используйте sublist() для вашей функции хвоста.

Ответ 3

При работе со списками, не являющимися непостоянными, совершенно безопасно и менее затратно использовать просто:

fun <T> List<T>.tail(): List<T> =
    if (isEmpty()) throw IllegalArgumentException("tail called on empty list")
    else subList(1, count())