テール関数を見つけようとしていますが、List<T>
見つかりませんでした。私はこれをやってしまった。
fun <T> List<T>.tail() = this.takeLast(this.size -1)
これを行うより良い方法はありますか?
テール関数を見つけようとしていますが、List<T>
見つかりませんでした。私はこれをやってしまった。
fun <T> List<T>.tail() = this.takeLast(this.size -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
あなたと@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
で試すことができるかどうかを確認します。の存在意義は、コレクションの怠惰な作業のためです。Sequence
Sequence
編集 2: どうやら sublist() はビューを作成するため、すでに遅延しています。基本的に、サブリストの実装を作成する方法を教えただけですが、末尾だけに絞り込みました。
したがって、その場合は、テール関数に sublist() を使用してください。
可変でないリストを操作する場合は、次のように単純に使用するのが完全に安全であり、メモリの消費も少なくなります。
fun <T> List<T>.tail(): List<T> =
if (isEmpty()) throw IllegalArgumentException("tail called on empty list")
else subList(1, count())