Scala: How to add, update, and remove elements with immutable Maps

This is an excerpt from the 1st Edition of the Scala Cookbook (partially modified for the internet). This is Recipe 11.16, “How to Add, Update, and Remove Elements with Immutable Maps”

Problem

You want to add, update, or delete elements when working with an immutable Scala Map.

Solution

Use the correct operator (method) for each purpose. Because you’re working with an immutable Map, remember to assign the results to a new Map variable.

To be clear about the approach, the following examples use an immutable Map with a series of val variables. First, create an immutable Map as a val:

scala> val a = Map("AL" -> "Alabama")
a: scala.collection.immutable.Map[String,String] = Map(AL -> Alabama)

Add one or more elements with the + method, assigning the result to a new Map variable during the process:

// add one element
scala> val b = a + ("AK" -> "Alaska")
b: scala.collection.immutable.Map[String,String] = Map(AL -> Alabama, AK -> Alaska)

// add multiple elements
scala> val c = b + ("AR" -> "Arkansas", "AZ" -> "Arizona")
c: scala.collection.immutable.Map[String,String] = Map(AL -> Alabama, AK -> Alaska, AR -> Arkansas, AZ -> Arizona)

To update a key/value pair with an immutable Map, reassign the key and value while using the + method, and the new values replace the old:

scala> val d = c + ("AR" -> "banana")
d: scala.collection.immutable.Map[String,String] = Map(AL -> Alabama, AK -> Alaska, AR -> banana, AZ -> Arizona)

To remove one element, use the - method:

scala> val e = d - "AR"
e: scala.collection.immutable.Map[String,String] = Map(AL -> Alabama, AK -> Alaska, AZ -> Arizona)

To remove multiple elements, use the - or -- methods:

scala> val f = e - "AZ" - "AL"
f: scala.collection.immutable.Map[String,String] = Map(AK -> Alaska)

Discussion

Depending on your needs, you can also declare an immutable Map as a var. Doing so has a dramatic difference on how you can treat the map:

scala> var x = Map("AL" -> "Alabama")
x: scala.collection.mutable.Map[String,String] = Map(AL -> Alabama)

// add one element
scala> x += ("AK" -> "Alaska"); println(x)
Map(AL -> Alabama, AK -> Alaska)

// add multiple elements
scala> x += ("AR" -> "Arkansas", "AZ" -> "Arizona"); println(x)
Map(AZ -> Arizona, AL -> Alabama, AR -> Arkansas, AK -> Alaska)

// add a tuple to a map (replacing the previous "AR" key)
scala> x += ("AR" -> "banana"); println(x)
Map(AZ -> Arizona, AL -> Alabama, AR -> banana, AK -> Alaska)

// remove an element
scala> x -= "AR"; println(x)
Map(AZ -> Arizona, AL -> Alabama, AK -> Alaska)

// remove multiple elements (uses varargs method)
scala> x -= ("AL", "AZ"); println(x)
Map(AK -> Alaska)

// reassign the map that 'x' points to
scala> x = Map("CO" -> "Colorado")
x: scala.collection.mutable.Map[String,String] = Map(CO -> Colorado)

It’s important to understand that when you create an immutable map as a var, you still have an immutable map. For instance, you can’t reassign an element in the map:

scala> x("AL") = "foo"
<console>:9: error: value update is not a member of scala.collection.immutable.Map[String,String]
              x("AL") = "foo"
              ^

What’s really happening in the previous examples is that because x was defined as a var, it’s being reassigned during each step in the process. This is a subtle but important distinction to understand. See Recipe 10.6, “Understanding Mutable Variables with Immutable Collections” for more information.