Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Idiomatic way of transforming a List<Pair<A, B>> into a Pair<List<A>, List<B>>

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

However, it feels like quite a hassle to achieve this. Knowing Kotlin, I feel there should be a way to make this a little bit more elegant and readable.

Is there a more idiomatic way of achieving this?

I know about associate, but this wouldn’t allow destructuring the resulting Pair and there could be issues with duplicate keys.

>Solution :

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()
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading