13

Suppose I have a list of persons and would like to have Map<String, Person>, where String is person name. How should I do that in kotlin?

Duncan McGregor
  • 17,665
  • 12
  • 64
  • 118
Yurii
  • 827
  • 2
  • 13
  • 23

2 Answers2

24

Assuming that you have

val list: List<Person> = listOf(Person("Ann", 19), Person("John", 23))

the associateBy function would probably satisfy you:

val map = list.associateBy({ it.name }, { it.age })
/* Contains:
 * "Ann" -> 19
 * "John" -> 23
*/

As said in KDoc, associateBy:

Returns a Map containing the values provided by valueTransform and indexed by keySelector functions applied to elements of the given array.

If any two elements would have the same key returned by keySelector the last one gets added to the map.

The returned map preserves the entry iteration order of the original array.

It's applicable to any Iterable.

Community
  • 1
  • 1
hotkey
  • 140,743
  • 39
  • 371
  • 326
  • `toMap()` has changed to `toMapBy()` in current Kotlin, can you please update the answer. – Jayson Minard Jan 06 '16 at 03:59
  • For other equivalents between `Stream.collect` and Kotlin, see http://stackoverflow.com/questions/34642254/what-is-the-java-8-stream-collect-equivalent-in-kotlin – Jayson Minard Jan 06 '16 at 20:37
  • @JaysonMinard, thanks, updated the answer, also used another `toMapBy` overload which is closer to `Collectors.toMap`. – hotkey Jan 06 '16 at 21:45
  • 1
    Coudn't find `List.toMapBy`... maybe missing an import. However `.keysToMap {transform(it)}` was exactly what I was looking for to replace `.stream().collect(Collectors.toMap(Function.identity(), {transform(it)}))`. – TWiStErRob Jan 20 '18 at 23:59
  • @TWiStErRob, the `toMapBy` function seems to have been renamed to [`associateBy`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/associate-by.html). Thanks for noticing that, I'll update the answer. – hotkey Jan 21 '18 at 00:52
  • Actually, don't use `keysToMap` or `associateBy(identity(), {...})` (`associateBy` is OK, `identity()` is not!), both of these are internal to Jetbrains (`org.jetbrains.kotlin.utils`), not public Kotlin API (`kotlin.*`). They lurked in via `gradle-kotlin-dsl` and `kotlin-compiler-embeddable`. Depending on these may cause ClassNotFoundExceptions. – TWiStErRob Jan 22 '18 at 00:26
4

Many alternatives in Kotlin :)

val x: Map<String, Int> = list.associate { it.name to it.age }
val y: Map<String, Int> = list.map { it.name to it.age }.toMap()
var z: Map<String, Int> = list.associateBy({ it.name }, { it.age })

The best option for this particular case IMO is the first as Lambdas are not needed but simple transformation.

Juan Rada
  • 3,513
  • 1
  • 26
  • 26