Kotlin List尾部功能

时间:2016-03-04 23:35:59

标签: kotlin kotlin-extension

我试图在List<T>中找到一个尾部函数,但我找不到任何函数。我最终这样做了。

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

有更好的方法吗?

3 个答案:

答案 0 :(得分:32)

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

答案 1 :(得分: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()

如果你真的需要它,我可以添加一个更新来制作最后三个成员函数,这样他们就不会制作热切的副本。

编辑: 注意:如果你遵循Kotlin迄今为止所遵循的约定,你就不会让List的尾巴变得懒惰,因为它们在List上的所有功能都是如此制作热切的副本。相反,特别是如果您使用headtail递归迭代列表,我会看到您是否可以某种方式在Sequence上尝试这个包装器的想法。 Sequence的整个存在点是对收藏品的懒惰工作。

编辑2: 显然sublist()创建了一个视图,因此已经是懒惰的。基本上,我刚刚教你如何创建子列表的实现,除了我把它缩小到尾部。

因此,在这种情况下,只需使用sublist()作为尾函数。

答案 2 :(得分:1)

如果使用非可变列表,则简单地使用它是绝对安全的,并且减少了内存消耗:

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