I currently have code with similar mechanics to the following
fun main() {
val listOfLists = listOf(listOf("1234", "1", "42"), listOf("hello", "there"))
val (lengths: List<List<Int>>, resultingListsOfLists: List<List<String>?>) =
listOfLists
.map {
val lengths = it.map { it.count() }
Pair(
lengths,
if (lengths.sum() > 5) {
// doing some transformation here in my original code,
// but for the sake of keeping it simple, just return `it`
it
} else {
null
}
)
}
.let { mapped ->
println(mapped)
Pair(mapped.map { it.first }, mapped.map { it.second })
}
println(lengths)
println(resultingListsOfLists)
}
which should output
[([4, 1, 2], [1234, 1, 42]), ([5, 5], [hello, there])]
[[4, 1, 2], [5, 5]]
[[1234, 1, 42], [hello, there]]
and it works sufficiently for my use case.
However, the last let
-part is a bit verbose. Knowing Kotlin, I feel there should be a way to make transforming List<Pair<A, B>>
to a Pair<List<A>, List<B>>
more concise and readable.
Is there a function in the stdlib to achieve this?
I know about associate
, but this wouldn't allow destructuring the resulting Pair and there could be issues with duplicate keys.
You are looking for unzip
- a method that converts List<Pair<T, U>>
to Pair<List<T>, List<U>>
. You can replace the final let
call with unzip
.
If you extract the "transformation" you do into another function, you can write something very readable, like it.takeIf { ... }?.run(::process)
.
listOfLists
.map {
val lengths = it.map(String::length)
lengths to (it.takeIf { lengths.sum() > 5 }?.run(::process))
}.unzip()