Map sorting by index


#1
val tags = mapOf("a" to arrayOf(1, 2, 3), "b" to arrayOf(4, 2), "c" to arrayOf(5, 2, 3)
tags.toSortedMap(compareByDescending { tags[it]!!.size })

Can someone help me understand how does this work internally?
The above code gives resulting map having only keys a and b, and overrides c.(because it is an array of size 3, which matches a)


#2

toSortedMap returns a java.util.TreeMap. This implementation assumes that if 2 objects are equal using the comparator then they are the same object, so

a.compareTo(b) == 0       <==>         a == b

That’s why it only adds one of the arrays of length 3. Which one depends on the iteration order of the first map which is undefined. I think mapOf returns a HashMap and therefor has a more or less random iteration order. It should be the same all the time but I don’t think there is any good way of guessing what it might be.


As you might have noticed there are a few areas where the documentation of the kotlin stdlib is not perfect. I guess this is one of them :wink:


You could use compareByDescending { ... }.thenBy { ... } as shown in the documentation
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/to-sorted-map.html


#3

Actually, this behavior is documented. The documentation states that toSortedMap returns a java.util.SortedMap. Since that is not part of the Kotlin Standard Library, it links to the Java documentation, which tends to be quite comprehensive. In particular:

Note that the ordering maintained by a sorted map (whether or not an explicit comparator is provided) must be consistent with equals if the sorted map is to correctly implement the Map interface. (See the Comparable interface or Comparator interface for a precise definition of consistent with equals .) This is so because the Map interface is defined in terms of the equals operation, but a sorted map performs all key comparisons using its compareTo (or compare ) method, so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal. The behavior of a tree map is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Map interface.


#4

Yes you’re right but that is what I meant by not perfect. You have to either know the specifics of the java types used in the background or click through multiple layers of documentation (ok in this case only one). It would not hurt the kdoc of the sdt-lib to repeat this restriction.


#5

The iteration order of the returned map is specified in the documentation of mapOf:

Entries of the map are iterated in the order they were specified.


#6

@niksw7, I presume this isn’t what you expected to get: a map with the entries sorted according to the specified order. Could you describe your use case in detail, why do you need such a map?