Confused about documentation of Kotlin's associateWith map transformation extension function

Trying to study collection transformations in Kotlin and I'm a bit confused by the documentation for the associateWith transformation extension function.

It says:

The basic association function associateWith() creates a Map in which the elements of the original collection are keys, and values are produced from them by the given transformation function. If two elements are equal, only the last one remains in the map.

Yet when I test this function with a list that contains duplicate elements i.e. they're equal, the last one gets excluded from the map, and only the first is the one that remains, contrary to what it says in the doc.

fun main() {
val numbers = listOf("one", "two", "three", "four", "five", "four")
val mapOfNumbers = numbers.associateWith { it.length }
println(mapOfNumbers) //the first "four" element is the one that remains in the map
}

Running this in the Kotlin Playground prints the following

{one=3, two=3, three=5, four=4, five=4}

Is the wording off in the documentation or am I missing something here with my train-of-thought?


Solution 1:

the last one gets excluded from the map, and only the first is the one that remains

You are not observing what you think you are here. You are looking at the string representation of the map's contents. Maps in general are unordered, so looking at the order is not something that will help here. Kotlin creates LinkedHashMaps most of the time by default in this sort of stdlib functions, so it preserves insertion order. Even if the second "four" overrides the first, it will still be placed in that position.

What the documentation means is that if there are duplicates, and if your transformation lambda gives different values for the duplicate keys, the last one wins. Here your lambda gives the same value for the same key, so you can't test this part of the doc with your current code.

Here is an example to test what the doc says:

val numbers = listOf("one", "two", "three", "four", "five", "four")

var order = 1
val mapOfNumbers = numbers.associateWith { order++ }
println(mapOfNumbers) // {one=1, two=2, three=3, four=6, five=5}