Ueli Hofstetter
Ueli Hofstetter

Reputation: 2524

How to destruct a Kotlin list into sublists?

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

Answers (4)

jivimberg
jivimberg

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

hluhovskyi
hluhovskyi

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

Todd
Todd

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

zsmb13
zsmb13

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

Related Questions