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
Yoursと@Vladimir Mironovのソリューションwillは機能しますが、元のリストの熱心なコピーが自動的に作成され(最初の要素が削除されます)、大きなリストの場合は非常に長い時間がかかります。インデックス調整を使用して最初の要素を無視し、そのメソッドをラップされたものに委譲するラッパー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
プロパティを作成しました
これらはすべて、なんらかの委任を行うのではなく、コレクションを手動で反復することによって実装できます。それがあなたの望むものなら、きっとあなたはそれを理解できると確信しています。
これで、headプロパティとtailプロパティは次のようになります。
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
の尾を遅延させないでください。 。代わりに、特にhead
とtail
を使用してリストを再帰的に反復している場合、Sequence
に対してこのラッパーのアイデアをどうにかして試してみることができます。 Sequence
の存在意義はすべて、コレクションの遅延作業にあります。
編集2:どうやらsublist()はビューを作成するため、すでに遅延しています。基本的には、末尾のみに絞り込んだことを除いて、サブリストの実装を作成する方法を説明しました。
したがって、その場合は、tail関数にsublist()を使用します。
変更不可能なリストを操作する場合、単純に使用する方が完全に安全で、メモリ消費も少なくなります。
fun <T> List<T>.tail(): List<T> =
if (isEmpty()) throw IllegalArgumentException("tail called on empty list")
else subList(1, count())