Home > Back-end >  How to use destructuring declarations to get multiple value from single map iteration?
How to use destructuring declarations to get multiple value from single map iteration?

Time:09-24

data class Person(val name: String, val age: String, val color: String)
val persons = listOf(Person("john", "20", "green"), Person("Mary", "20", "blue"))
val names = persons.map {it.name}
val ages = persons.map {it.age}
val colors = persons.map {it.color}
// I will need 3 iteration to get my names and ages and colors
val personsMap = persons.map { it.name to it.age }
val (names2, ages) = personsMap.unzip()
// I am using 1 iteration but with Map and uzip(), I can get names2, 
// ages within a single iteration
// Now if I wish to get color
// By using map, or alternatives call helper.. can I retrieve names, 
// ages and colors at one go
// I do know that we can use iteration forEachloop and add into a 
// set/list, but  
// are there better way of doing it
// val (names, ages, colors)

What are the alternative way to write to get multiple value in a single iteration to get its list from destructing.

CodePudding user response:

In order to collect lists of different properties, at least one iteration is required. this can be done by defining an extension function as

fun List<Person>.collectProperties(): Triple<List<String>, List<String>, List<String>>{
    val (names, ages, colors) = listOf(mutableListOf<String>(), mutableListOf(), mutableListOf())
    this.forEach { person ->
        names.add(person.name)
        ages.add(person.age)
        colors.add(person.color)
    }
    return Triple(names, ages, colors)
}

now you can use this as

val persons = listOf(Person("john", "20", "green"), Person("Mary", "20", "blue"))
val(names, ages, colors) = persons.collectProperties()

CodePudding user response:

Your toList() call is redundant, so you're iterating 3 times instead of twice.

I can't think of a way to do this with a single iteration using standard library higher-order functions. You could write a function like this that maps and unzips in one step so it only iterates once:

inline fun <T, U, V> Iterable<T>.doubleMap(transform: (T) -> Pair<U, V>): Pair<List<U>, List<V>> {
    val size = if (this is Collection<*>) size else 10
    val listU = ArrayList<U>(size)
    val listV = ArrayList<V>(size)
    for (t in this) {
        with (transform(t)) {
            listU  = first
            listV  = second
        }
    }
    return listU to listV
}
  • Related