Kotlin Maps

Maps are data structures that associate keys with values. When we lookup values in a map, we specify a key and the map returns an associated value. It’s easy to think of a map being like a phone book. When we want to call somebody, and we only know their name but not their phone number, we find their name in the phone book and the phone book has their number associated with a name.

In the phone book example, we can think of a person’s name as the key and the phone number as the value. In Kotlin, we could make such a map like so:

val phoneBook = mapOf("Bob Belcher" to 8675309, "Linda Belcher" to 8675310)
println(phoneBook["Bob Belcher"]) //prints 8675309
println(phoneBook["Linda Belcher"]) //prints 8675310

We create a phoneBook object using the mapOf(), or mutableMap(), and then specifying any number of pair arguments. Each pair is written key to value so in our example, “Bob Belcher” to 8675309 or “Linda Belcher” to 8675309. When we need to access an item in the map, we use the index operator [] and put the key inside of the operator. In other words, to print Bob’s number, we would write phoneBook[“Bob Belcher”].

When we do not know all of the values we are placing in the map ahead of time, we can use mutableMapOf(). This is the read/write version of the map that has methods to add items and remove items from a map. Let’s look at a code example to see how we add items and remove them from a mutableMap.

//Type is needed when we do not specify arguments in mutableMapOf()
val phoneNumbers = mutableMapOf<String, Int>()

//Use the put method to add items
phoneNumbers.put("Bob Belcher", 8675309)
phoneNumbers.put("Linda Belcher", 8675310)

//Use the remove method to remove items
phoneNumbers.remove("Linda Belcher")

In this case, we use the put() method to add items to the map. The first argument is the key and the second argument is the value. The remove method is the opposite operation. It takes the key as the only argument and removes the entry from the map.

Keys in a map have to be unique. If we use put() with a key that already exists, we will overwrite the current value of the map. This normally isn’t a problem, but it can end up being a source of bugs, especially for new learners. We can protect ourselves from such accidents by converting a mutableMap into a an immutableMap.

//Change phoneNumbers into a read only map
val readOnly = phoneNumbers.toMap() 

Map Example Problem

Couting the frequency of words in text is a common use case for maps. This program counts the number of times certain words appear from an except of “Green Eggs and Ham” by Dr. Suess.

package ch6.maps

fun main(args : Array<String>){
    val paragraph = """
        I am Sam.
        Sam I am.

        That Sam-I-am!
        That Sam-I-am!
        I do not like
        That Sam-I-am!

        Do you like
        Green eggs and ham?

        I do not like them,
        I do not like
        Green eggs and ham.
    //Remove punctuation and new line characters
    val cleanParagraph =
            paragraph.replace(".", "")
                    .replace(",", "")
                    .replace("?", "")
                    .replace("\n", "")

    //Split cleanParagraph into a List
    val words = cleanParagraph.split(" ")
    //Create an empty Map
    val wordCounts = mutableMapOf<String, Int>()
    //We have a few operations on the next line
    //1) Iterate through words
    //2) Check if the word has been found in wordCounts
    //3) Put an entry into word counts if the word wasn't found
    //4) Otherwise, update the entry found in wordCounts by 1
    words.forEach( { it -> wordCounts.put(it, wordCounts.getOrElse(it, { 0 }) + 1) })
    //Now print out the words with their frequencies


{=93, Do=1, Green=2, I=5, Sam=2, Sam-I-Am=1, Sam-I-am!=3, That=3, am=2, and=2, do=3, eggs=2, ham=2, like=4, not=3, them=1, you=1}

Kotlin Koans—Part 20

Grouping objects by a property and storing them into a map is a challenge that all developers have faced at some point in time. For example, you may have a collection of Customers and you wish to find out which Customers live in each city. Basically, you want a map where City is the key and a Collection of Customers associated with that City is the value.

This was exactly the problem that Kotlin Koans tutorial had me do.

fun Shop.groupCustomersByCity(): Map {
    // Return a map of the customers living in each city
    return customers.groupBy { it.city }

I was able to arrange all of the Customers by city with just one line of Kotlin code. The related Java code wasn’t that difficult either, but I did have to search for the solution since it wasn’t quite as clear as the Kotlin approach.

public static Map groupCustomersByCity(Shop shop){
    return shop.getCustomers().stream().collect(Collectors.groupingBy(Customer::getCity));

What helped me with the Kotlin approach was that since the groupBy method was direclty on the Collection object, my IDE was able to supply me with the groupBy method. That’s not the case with the Java approach since it’s using a static method on the Collectors class. It also didn’t occur to me to use the collect method on the Stream object either. I was looking for something that said group in it.

You can click here to see Part 19.