Kotlin Collect example #6 - group people by age, print age and names together


// Java:
Map<Integer, String> map = persons
                p -> p.age,
                p -> p.name,
                (name1, name2) -> name1 + ";" + name2));

// {18=Max, 23=Peter;Pamela, 12=David}    

Ok, a more interest case here for Kotlin. First the wrong answers to explore variations of creating a Map from a collection/sequence:

// Kotlin:
val map1 = persons.map { it.age to it.name }.toMap()
// output: {18=Max, 23=Pamela, 12=David} 
// Result: duplicates overridden, no exception similar to Java 8

val map2 = persons.toMap({ it.age }, { it.name })
// output: {18=Max, 23=Pamela, 12=David} 
// Result: same as above, more verbose, duplicates overridden

val map3 = persons.toMapBy { it.age }
// output: {18=Person(name=Max, age=18), 23=Person(name=Pamela, age=23), 12=Person(name=David, age=12)}
// Result: duplicates overridden again

val map4 = persons.groupBy { it.age }
// output: {18=[Person(name=Max, age=18)], 23=[Person(name=Peter, age=23), Person(name=Pamela, age=23)], 12=[Person(name=David, age=12)]}
// Result: closer, but now have a Map<Int, List<Person>> instead of Map<Int, String>

val map5 = persons.groupBy { it.age }.mapValues { it.value.map { it.name } }
// output: {18=[Max], 23=[Peter, Pamela], 12=[David]}
// Result: closer, but now have a Map<Int, List<String>> instead of Map<Int, String>

And now for the correct answer:

// Kotlin:
val map6 = persons.groupBy { it.age }.mapValues { it.value.joinToString(";") { it.name } }

// output: {18=Max, 23=Peter;Pamela, 12=David}
// Result: YAY!!

We just needed to join the matching values to collapse the lists and provide a transformer to joinToString to move from Person instance to the Person.name.