Start learning free

LESSON 108 OF 414 · DICTIONARIES

Updating Dictionary Values in Scala: Mutable and Immutable Maps

Lesson Read the full explanation

Immutable maps return a new map when updated. Mutable maps can be changed in place.

var ages = Map("Ana" -> 12)
ages = ages.updated("Ana", 13)
println(ages("Ana"))

Assignment
Follow the Coding Tutorial and practice using maps.


Hint
Use key -> value pairs when creating a map.


STEP 1 OF 1
    Ctrl + Enter to check

    SCALA · DICTIONARIES

    Updating Dictionary Values in Scala, explained

    Two kinds of map, two ways to update

    Scala has two families of maps, and updating works differently in each.

    An immutable Map, the default, can't be changed. To "update" it you call updated, which returns a new map with the change and leaves the original as it was. You must keep the new map somewhere, typically in a var:

    var ages = Map("Ana" -> 12)
    ages = ages.updated("Ana", 13)
    println(ages("Ana"))   // 13
    

    A mutable map, from scala.collection.mutable, changes in place. Assigning to a key replaces its value in the same map object, so a val is enough:

    val scores = scala.collection.mutable.Map("Alice" -> 95, "Bob" -> 87)
    scores("Alice") = 99
    println(scores("Alice"))   // 99
    

    The assignment syntax

    The line scores("Alice") = 99 looks like assigning to a function call. Scala translates it into scores.update("Alice", 99), so both spellings do the same thing. The same rule makes buffer(0) = 5 work on arrays and buffers.

    The assignment sets the value for the key and returns nothing. If the key already exists, its value is replaced. If it doesn't, a new entry is added:

    val scores = scala.collection.mutable.Map("Alice" -> 95, "Bob" -> 87)
    scores("Alice") = 99    // replaces the value, size stays 2
    scores("Dan") = 50      // adds a new entry, size becomes 3
    println(scores.size)    // 3
    

    The exercise

    The starting code has a mutable map with two entries. The task is to change Alice's score to 99.

    1. Keep the existing scores declaration unchanged.
    2. Below it, write scores("Alice") = 99. The key goes in parentheses, and the new value goes after the =.
            val scores = scala.collection.mutable.Map("Alice" -> 95, "Bob" -> 87)
    
            scores("Alice") = 99
    

    Afterwards scores("Alice") is 99 and scores("Bob") is still 87. The name scores was declared with val and was never reassigned: only the contents of the map changed.

    Reading the result back

    After an update, the new value is visible immediately through any name that refers to the same mutable map. Two names that point at one map share its changes, so a function that receives scores and runs scores("Alice") = 99 changes the caller's map too. An immutable map never behaves like this, which makes it safer to pass around when you don't want surprises.

    Update based on the old value

    A common pattern is to compute the new value from the current one, such as counting occurrences. The key might not exist yet, so read it with getOrElse and a starting value:

    val counts = scala.collection.mutable.Map[String, Int]()
    for (word <- List("a", "b", "a")) {
        counts(word) = counts.getOrElse(word, 0) + 1
    }
    println(counts.toList.sorted)   // List((a,2), (b,1))
    

    Reading with counts(word) instead would throw NoSuchElementException the first time a word appears, because there is no entry to read yet.

    Common mistakes

    • Using this syntax on an immutable map. With a plain Map(...), the line ages("Ana") = 13 is rejected by the compiler, because an immutable map has no update method. Either switch to a mutable map or use updated.
    • Forgetting to keep the result of updated. Writing ages.updated("Ana", 13) on its own line builds a new map that nobody keeps. ages still holds 12.
    • Misspelling the key. An update with "alice" doesn't change "Alice". It adds a second entry under the new key.
    • Using := or =>. The update is a plain =. The arrow -> is only for building pairs.

    Other ways to change a mutable map

    val scores = scala.collection.mutable.Map("Alice" -> 95, "Bob" -> 87)
    
    scores.update("Bob", 1)   // same as scores("Bob") = 1
    scores -= "Alice"         // removes the entry for "Alice"
    println(scores)           // HashMap(Bob -> 1)
    

    Key takeaways

    • On a mutable map, map(key) = value replaces the value for an existing key and adds an entry for a new one.
    • On an immutable map, updated returns a new map, so store it in a var or another val.
    • val fixes the name, not the contents of a mutable map.
    Keep going with ScalaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free