2016-03-04 80 views
12

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

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

有没有更好的方法来做到这一点?

回答

22

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 
+5

如果您不想复制列表(在很多情况下很好,CPU缓存和较小的列表都可以),那么请查看Java标准“子列表”以获取扩展https:/ /docs.oracle.com/javase/7/docs/api/java/util/List.html#subList(int,%20int)(根据下面评论中的@hotkey) –

3

你和@Vladimir Mironov的解决方案工作,但他们自动创建原始列表的渴望副本(sans第一elem ent),这对于较大的列表可能需要很长时间。我会用一个包装定义它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 
} 

您可能会注意到在部分功能后的评论还是最终作出的渴望复制。为了简单起见,我只做了这个。为了记忆,我做了一个lazytailList属性

它们都可以通过手动遍历集合来实现,而不是做某种委托。如果这是你想要的,我相信你可以弄明白。

就这样,头部和尾部的属性变成这样:

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() 

如果你真的需要它,我可以添加一个更新,使过去的三个成员函数,使他们不急于做副本。

编辑: 注意:如果你遵循的科特林沿袭至今的惯例,你不会让List的尾巴偷懒,像这样的,因为他们所有的功能上List让渴望副本。相反,特别是如果您使用headtail递归遍历列表,我会看到您是否可以以某种方式在Sequence上尝试此封装器的想法。 Sequence的整个存在点是对收藏的懒惰工作。编辑2: 显然sublist()创建一个视图,因此已经是懒惰的。从本质上讲,我只是教你如何创建子列表的实现,除了我缩小到只有尾部。

所以,在这种情况下,只需使用sublist()为您的尾巴功能。

+1

为什么不使用Java的'sublist'?它完全一样,它创建了原始列表的视图。 https://docs.oracle.com/javase/7/docs/api/java/util/List.html#subList(int,%20int) – hotkey

+0

这不就是序列的用途吗? –

+1

@hotkey我没有意识到子列表是意见。很高兴知道。 –