34

テール関数を見つけようとしていますが、List<T>見つかりませんでした。私はこれをやってしまった。

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

これを行うより良い方法はありますか?

4

4 に答える 4

49

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
于 2016-03-04T23:54:08.413 に答える
3

あなたと@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()

本当に必要な場合は、最新の 3 つのメンバー関数を作成して熱心なコピーを作成しないようにするための更新を追加できます。

編集: 注: これまで Kotlin が従ってきた規則に従った場合、のすべての関数が熱心なコピーを作成するためList、 の末尾をこのように遅延させることはありません。List代わりに、特に and を使用headしてリストを再帰的に反復する場合は、このラッパーのアイデアを何らかの方法tailで試すことができるかどうかを確認します。の存在意義は、コレクションの怠惰な作業のためです。SequenceSequence

編集 2: どうやら sublist() はビューを作成するため、すでに遅延しています。基本的に、サブリストの実装を作成する方法を教えただけですが、末尾だけに絞り込みました。

したがって、その場合は、テール関数に sublist() を使用してください。

于 2016-03-05T04:51:47.280 に答える
1

可変でないリストを操作する場合は、次のように単純に使用するのが完全に安全であり、メモリの消費も少なくなります。

fun <T> List<T>.tail(): List<T> =
    if (isEmpty()) throw IllegalArgumentException("tail called on empty list")
    else subList(1, count())
于 2019-04-27T09:14:12.830 に答える