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, Sam-I-Am 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 println(wordCounts.toSortedMap()) }
Output
{=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}