kotlindictionarymutablemap

How to iterate over a Map in Kotlin


So I am new to Kotlin and I am wondering what's the standard way of iterating a Map. I have tried different ways and all of them seem to work, but I don't know if there's one better than the rest or there are some differences that I am not aware of.

    var mutMap = mutableMapOf("one" to 1, "two" to 2, "tree" to 3, "four" to 4, "five" to 5)

    mutMap.forEach { entry -> println(entry) }

    mutMap.iterator().forEach { entry -> println(entry) }

    mutMap.entries.forEach { entry -> println(entry) }

    mutMap.entries.iterator().forEach { entry -> println(entry) }

    for (entry in mutMap) { println(entry) }

    for (entry in mutMap.entries) { println(entry) }

    for (entry in mutMap.iterator()) { println(entry) }

    for (entry in mutMap.entries.iterator()) { println(entry) }

Also, if I wanted to also delete an entry while iterating over them, none of them would work, right?


Solution

  • If you browse through Kotlin's Collections package there is a whoooole lot of stuff you can use, yeah! Lots of different functions that let you drill down into specific pieces of data (like keys or values vs entries, or providing indices) or getting specific behaviour as you process a collection.

    The examples you've given are all basically the same thing though. Here's the page for all the forEach functions on the various types of collections:

    inline fun <T> Array<out T>.forEach(action: (T) -> Unit)
    (source)
    
    // a bunch of other Kotlin-specific Array types
    
    inline fun <T> Iterable<T>.forEach(action: (T) -> Unit)
    
    inline fun <K, V> Map<out K, V>.forEach(
        action: (Entry<K, V>) -> Unit)
    
    inline fun <T> Iterator<T>.forEach(operation: (T) -> Unit)
    

    And here's the source code for those (there's a source link under every function's main page, useful to know about! You can see exactly how they work)

    public inline fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit {
        for (element in this) action(element)
    }
    
    public inline fun <K, V> Map<out K, V>.forEach(action: (Map.Entry<K, V>) -> Unit): Unit {
        for (element in this) action(element)
    }
    
    public inline fun <T> Iterator<T>.forEach(operation: (T) -> Unit): Unit {
        for (element in this) operation(element)
    }
    

    So really they're all wrappers for a basic for loop, which as the documentation says, iterates through anything that provides an iterator. Your examples are all basically the same thing that's happening, just jumping in at various points in the forEach -> basic for loop -> get an iterator process.

    The only part that's different is when you call entries, which returns a Set holding the key/value Entry pairs - so you're iterating over that, rather than the Map itself. But wait, what does happen if you call iterator() on a Map?

    public inline operator fun <K, V> Map<out K, V>.iterator(): Iterator<Map.Entry<K, V>> = entries.iterator()
    

    It uses entries itself! So yeah they're all the same thing


    Really I think it comes down to this