Reputation: 2524
How can I destruct a list in Kotlin into two sublists? Currently I do something like this:
val (first, rest) = listOf("one", "two", "three")
But doing so, first is "one" and rest is "two". I want them to be first =["first"]
and rest = ["two", "three"]
.
Is this even possible using this "destructor" syntax?
Upvotes: 21
Views: 8563
Reputation: 890
This can be achieved using an extension function. Here's my take:
val <T> List<T>.tail: List<T>
get() = subList(1, size)
val <T> List<T>.head: T
get() = first()
fun <T> List<T>.headTail() = Pair(head, tail)
First I'm defining the extensions properties head
and tail
so you can do:
val list = listOf("one", "two", "three")
println(list.head) // "one"
println(list.tail) // ["two", "three"]
(If you don't like having the extension properties you can simply inline the code in the headTail
function)
Finally the headTail
function can be used like this:
val (head, tail) = listOf("one", "two", "three").headTail()
println(head) // "one"
println(tail) // ["two", "three"]
Notice that I'm using subList
for the tail instead of drop(1)
to prevent copying the list every time.
Upvotes: 4
Reputation: 10106
It is possible by creating component2
operator as extension method manyally:
operator fun <T> List<T>.component2(): List<T> = drop(1)
fun destrcutList() {
val (first: String, second: List<String>) = listOf("1", "2", "3")
}
You need create extension method only for component2
, component1
will be used as previously.
Types can be omitted:
fun destrcutList() {
val (first, second) = listOf("1", "2", "3")
println(second[0]) // prints "2"
}
One important note: in case if you declare extension method in another package you have to import function manually:
import your.awesome.package.component2
Upvotes: 3
Reputation: 31700
You could also define your own component functions:
operator fun <T> List<T>.component2(): List<T> = this.drop(1)
And then this works as expected:
val (head, rest) = listOf("one", "two", "three")
println(head) // "one"
println(rest) // ["two", "three"]
Upvotes: 7
Reputation: 89548
Destructuring translates to calling component1
, component2
, etc. operator functions on an object. In the case of a List
, these are defined as extensions in the standard library, and return the Nth element respectively.
You could define your own extension extension that splits the list as desired and returns a Pair
, which can then be destructured:
fun <T> List<T>.split() = Pair(take(1), drop(1))
This could be used like so:
val (first, rest) = listOf("one", "two", "three").split()
println(first) // [one]
println(rest) // [two, three]
Perhaps naming it something better than split
would be smart though.
Upvotes: 21