Search code examples
javakotlintreemaplinkedhashmap

Problem with Kotlin reordering LinkedHashMap keys


My goal is to get keys from a LinkedHashMap in the order that they are stored in the Map in Kotlin. I have this working in Java, but Kotlin is doing it differently.

I have a base class with 2 subclasses. One subclass sets the map to LinkedHashMap and the other to TreeMap. Both the ordered and unordered subclasses have all their functionality in the superclass. The base class uses a Map in Java, a MutableMap in Kotlin because I need to mutate the map frequently. How do I get the keys from a MutableMap in order in Kotlin if I am using a LinkedHashMap as the base? I can see they are in order when using the debugger.

I am using a sealed base class with 2 subclasses, and whether or not the elements are sorted by order is the difference between the subclasses.

Here is the working Java code:

protected Map<T, Double> map; 

if (comparable) {
    this.map = new TreeMap<>();
} else {
    this.map = new LinkedHashMap<>();
}

public List<T> getKeys() {
    return new ArrayList<>(this.map.keySet());
}

and the broken Kotlin code:

protected var map: MutableMap<T, Double>

map = if (comparable) TreeMap() else LinkedHashMap()

val getKeys = ArrayList(map.keys)

I tried using an iterator, but the iterator does not reset! NoSuchElement when there should be?

        var keys = map.iterator
        assert(keys.next().key == 0)
        assert(keys.next().key == 1)
        assert(keys.next().key == 2)
        pf.swapPositions(2, 1)
        keys = map.iterator
        assert(keys.next().key == 0)
        assert(keys.next().key == 2)
        assert(keys.next().key == 1)
val iterator = map.iterator()

Solution

  • The only difference I can see is that val getKeys is not at all equivalent to Java's public List<T> getKeys(); that would be

    fun getKeys() = ArrayList(map.keys)
    

    or

    val keys get() = ArrayList(map.keys)
    

    The code you wrote evaluates ArrayList(map.keys) only once, during construction, when the map is likely empty.

    This may not be the only problem; if it still doesn't work after you fix it, please see https://stackoverflow.com/help/minimal-reproducible-example.

    Sidenote: in Kotlin, it's more idiomatic to write map.keys.toList or map.keys.toMutableList instead of directly using the ArrayList constructor unless you really need an ArrayList in particular.