Scala immutable Map class: methods, examples, and syntax

This page contains a large collection of examples of how to use the Scala Map class, including most of the methods that are available on a Vector. (Currently well over 100 examples.)

Back to top

Introduction

A Scala Map is a collection of unique keys and their associated values (i.e., a collection of key/value pairs), similar to a Java Map, Ruby Hash, or Python dictionary.

On this page I’ll demonstrate examples of the immutable Scala Map class. If you’re new to the immutable world, “immutable” means that you can’t change the contents of the map, and you can’t resize it. The way you work with an immutable map is to specify updates to it as you assign the changed result to a new variable.

Back to top

How to create an immutable Scala Map class instance

The immutable Map class is in scope by default, so you can create an immutable map without an import statement:

val states = Map(
    "AK" -> "Alaska",
    "AL" -> "Alabama", 
    "AR" -> "Arizona"
)

Here’s what it looks like in the Scala REPL:

scala> val states = Map(
     |     "AK" -> "Alaska",
     |     "AL" -> "Alabama", 
     |     "AR" -> "Arizona"
     | )
states: scala.collection.Map[String,String] = Map(AK -> Alaska, AL -> Alabama, AR -> Arizona)

Note about the syntax

The syntax that’s used inside the parentheses in a map creates a Tuple2:

"AL" -> "Alabama"    # (String, String) = (AL,Alabama)

Because you can also declare a Tuple2 as ("AL", "Alabama"), you may (rarely) see maps created like this:

val states = Map(
    ("AK", "Alaska"),
    ("AL", "Alabama"),
    ("AR", "Arizona")
)
Back to top

Adding elements to a Map (+, ++)

Use + or ++.

+ examples

Add one or more key/value pairs with + (while assigning the result to a new val):

val a = Map(1 -> "one")      # Map(1 -> one)
val b = a + (2 -> "two")     # Map(1 -> one, 2 -> two)
val c = b + (
    3 -> "three",
    4 -> "four"
)
# c: Map(1 -> one, 2 -> two, 3 -> three, 4 -> four)

In the OOP world you can also create a variable as a var and then reassign the result back to the same variable name:

var a = Map(1 -> "one")      # Map(1 -> one)
a = a + (2 -> "two")         # Map(1 -> one, 2 -> two)
a = a + (
    3 -> "three",
    4 -> "four"
)
# a: Map(1 -> one, 2 -> two, 3 -> three, 4 -> four)

++ examples

Use ++ to add a Traversable[(K,V)] to the map:

val a = Map(
    1 -> "one",
    2 -> "two",
)
val b = Map(
    3 -> "three",
    4 -> "four"
)
a ++ b    # Map(1 -> one, 2 -> two, 3 -> three, 4 -> four)

val c = List(
    3 -> "three",
    4 -> "four"
)
a ++ c    # Map(2 -> two, 4 -> four, 1 -> one, 3 -> three)
Back to top

Removing elements from a Map (-, --)

Use - or --.

- examples

Remove one or more elements by key with -:

val a = Map(
    1 -> "one",
    2 -> "two",
    3 -> "three",
    4 -> "four"
)

a - 4         # Map(1 -> one, 2 -> two, 3 -> three)
a - 3 - 2     # Map(1 -> one, 4 -> four)

-- examples

Use -- to remove multiple elements by specifying the keys in a sequence (technically a GenTraversableOnce[K], like Array, ArrayBuffer, Seq, Vector, Set, etc.):

val a = Map(
    1 -> "one",
    2 -> "two",
    3 -> "three",
    4 -> "four"
)

a -- Array(3,4)     # Map(1 -> one, 2 -> two)
a -- Seq(1,2)       # Map(3 -> three, 4 -> four)
a -- Set(1,4)       # Map(2 -> two, 3 -> three)
Back to top

How to access Map elements

Access map elements as shown here, but beware that this approach can throw an NoSuchElementException:

val states = Map(
    "AK" -> "Alaska",
    "AL" -> "Alabama",
    "AZ" -> "Arizona"
)

val az = states("AZ")      # Arizona
val foo = states("FOO")    # java.util.NoSuchElementException: key not found: FOO

Solutions for NoSuchElementException

Possible solutions:

  • Use withDefaultValue(a) with a sub-type of Map
  • get (returns an Option)
  • getOrElse
  • contains
  • isDefinedAt

Use withDefaultValue(a) with a sub-type of Map

The base immutable Map trait doesn’t have a withDefaultValue method, but some of its subclasses do:

# SortedMap
import collection.immutable.SortedMap
val a = SortedMap(1 -> "one")           # SortedMap[Int,String] = Map(1 -> one)
a(1)                                    # 1
a(2)                                    # throws a java.util.NoSuchElementException exception

val a = SortedMap(1 -> "one").withDefaultValue("not found")
a(1)                                    # 1
a(2)                                    # not found

# ListMap
import collection.immutable.ListMap
val a = ListMap(1 -> "one").withDefaultValue("not found")
a(1)                                    # 1
a(2)                                    # not found

Other possible solutions

The following examples assume you have this map:

val states = Map(
    "AK" -> "Alaska",
    "AL" -> "Alabama"
)

get:

states.get("AK")     # Some(Alaska)
states.get("foo")    # None

getOrElse:

states.getOrElse("AK", "No such state")     # Alaska
states.getOrElse("foo", "No such state")    # No such state

contains and isDefinedAt:

states.contains("AK")        # true
states.contains("foo")       # false

states.isDefinedAt("AK")     # true 
states.isDefinedAt("foo")    # false

Can do this, but it’s just a long form of getOrElse:

if (states.contains(maybeState)) states(maybeState) else "No such state"
Back to top

How to update immutable Map elements

Use updated:

val a = Map(
    1 -> "one",
    2 -> "two",
    3 -> "three"
)

val b = a.updated(3, "THREE!")     # Map(1 -> one, 2 -> two, 3 -> THREE!)
Back to top

How to iterate/loop over a Scala Map

val map = Map(
    1 -> "one",
    2 -> "two",
    3 -> "three"
)

# for
scala> for ((k,v) <- map) printf("key: %s, value: %s\n", k, v)
key: 1, value: one
key: 2, value: two
key: 3, value: three

# foreach (tuples)
scala> map.foreach(x => println (x._1 + "-->" + x._2))
1-->one
2-->two
3-->three

# foreach (foreach and case)
scala> map.foreach {case (key, value) => println (key + "-->" + value)}
1-->one
2-->two
3-->three

# foreach key
scala> map.keys.foreach(println)
1
2
3

# foreach value
scala> map.values.foreach(println)
one
two
three
Back to top

Getting keys and values from a Map

Given this map:

val states = Map(
    "AK" -> "Alaska", 
    "AL" -> "Alabama",
    "AR" -> "Arkansas"
)

Keys:

states.keySet               # Set[String] = Set(AK, AL, AR)
states.keys                 # Iterable[String] = Set(AK, AL, AR)
states.keysIterator         # Iterator[String] = non-empty iterator

Values:

states.values               # Iterable[String] = MapLike.DefaultValuesIterable(Alaska, Alabama, Arkansas)
states.valuesIterator       # Iterator[String] = non-empty iterator
Back to top

Test for existence of keys or values in a Map

Given this map:

val states = Map(
    "AK" -> "Alaska",
    "IL" -> "Illinois",
    "KY" -> "Kentucky"
)

Test for existence of a key:

states.contains("foo"))     # false

Or get the keys as a set, iterable, or iterator, which you can then search:

states.keySet               # Set[String] = Set(AK, AL, AR)
states.keys                 # Iterable[String] = Set(AK, AL, AR)
states.keysIterator         # Iterator[String] = non-empty iterator

Test for existence of a value:

states.valuesIterator.exists(_.contains("Alaska"))     # true
states.valuesIterator.exists(_.contains("foo"))        # false
Back to top

Map filtering methods

This lesson covers the immutable Map class, so you don’t remove elements from it. Instead, you describe how to remove elements as you apply a method to the map and assign the results to a new collection.

Method Returns
drop(n) All elements after the first n elements
dropRight(n) All elements except the last n elements
dropWhile(p) Drop the first sequence of elements that matches the predicate p
filter(p) All elements that match the predicate p
filterNot(p) All elements that do not match the predicate p
filterKeys(p) All elements where the keys match the predicate p
find(p) The first element that matches the predicate p
head The first element; can throw an exception if the Map is empty
headOption The first element as an Option
init All elements except the last one
last The last element; can throw an exception if the Map is empty
lastOption The last element as an Option
slice(f,u) A sequence of elements from index f (from) to index u (until)
tail All elements after the first element
take(n) The first n elements
takeRight(n) The last n elements
takeWhile(p) The first subset of elements that matches the predicate p

Examples

Examples of filtering methods on a Scala Map:

val a = Map(
    1 -> "one",
    2 -> "two",
    3 -> "three"
)

a.drop(1)                        # Map(2 -> two, 3 -> three)
a.dropRight(1)                   # Map(1 -> one, 2 -> two)
a.dropWhile(t => t._1 < 3)       # Map(3 -> three)

a.filter(t => t._1 > 1)          # Map(2 -> two, 3 -> three)
a.filter(t => t._2 == "two")     # Map(2 -> two)
a.filterNot(t => t._1 > 1)       # Map(1 -> one)

a.filter { case (k,v) =>
    v == "two"
}
# result: Map(2 -> two)

a.filterKeys(_ > 1)              # Map(2 -> two, 3 -> three)
a.filterKeys(Set(1,3))           # Map(1 -> one, 3 -> three)

a.find(t => t._1 > 1)            # Some((2,two))
a.head                           # (1,one)
a.headOption                     # Some((1,one))
a.init                           # Map(1 -> one, 2 -> two)
a.last                           # (3,three)
a.lastOption                     # Some((3,three))

a.slice(0,0)                     # Map()
a.slice(0,1)                     # Map(1 -> one)
a.slice(0,2)                     # Map(1 -> one, 2 -> two)
a.slice(1,1)                     # Map()
a.slice(1,2)                     # Map(2 -> two)
a.slice(1,3)                     # Map(2 -> two, 3 -> three)

a.tail                           # Map(2 -> two, 3 -> three)
a.take(1)                        # Map(1 -> one)
a.takeRight(1)                   # Map(3 -> three)
a.takeWhile(t => t._1 < 3)       # Map(1 -> one, 2 -> two)

A note about the Map/filter syntax

Note that although the Scaladoc shows this signature for filter:

def filter(p: ((K, V)) ⇒ Boolean): Map[K, V] 

this syntax does not work:

scala> a.filter( (k,v) => k > 1 )
<console>:13: error: missing parameter type
Note: The expected type requires a one-argument function accepting a 2-Tuple.
      Consider a pattern matching anonymous function, `{ case (k, v) =>  ... }`
       a.filter( (k,v) => k > 1 )
                  ^
Back to top

Map transformer methods

A transformer method is a method that constructs a new collection from an existing collection.

Method Returns
collect(pf) Applies the partial function pf to all elements of the map, returning elements for which the function is defined
collectFirst(pf) Applies the partial function pf to the first element of the map for which the partial function pf is defined, and returns the result of its application
flatten TODO
flatMap(f) TODO
map(f) A new map by applying the function f to each element in the map
mapValues(f) A new map by applying the function f to each value in the map
to* A series of methods that transform the map to other collections
updated(k,v) A new map with the value at key k replaced with the new value v
zipAll(i,a,b) TODO i = Iterable, a = type A, b = type B
zip(c) A map created by combining corresponding elements with the given Iterable collection c
zipWithIndex A map created by zipping this map with its indices
val a = Map(
    1 -> "one",
    2 -> "two",
    3 -> "three"
)

a.collect{case (k,v) => (k*2, v)}         # Map(2 -> one, 4 -> two, 6 -> three)
a.collect{case (k,v) => k > 1}            # List(false, true, true)

a.collectFirst{case (k,v) => (k*2, v)}    # Some((2,one))

a.map(t => (t._1*2, t._2))                # Map(2 -> one, 4 -> two, 6 -> three)
a.map(t => t._1*2)                        # List(2, 4, 6)
a.map{case (k,v) => (k*2, v)}             # Map(2 -> one, 4 -> two, 6 -> three)
a.map{case (k,v) => k*2}                  # List(2, 4, 6)
a.map{case (k,v) => v.toUpperCase}        # List(ONE, TWO, THREE)

a.mapValues(_.toUpperCase)                # Map(2 -> TWO, 1 -> ONE, 3 -> THREE)

a.toArray           # Array[(Int, String)]                = Array((2,two), (1,one), (3,three))
a.toBuffer          # mutable.Buffer[(Int, String)]       = ArrayBuffer((2,two), (1,one), (3,three))
a.toIndexedSeq      # immutable.IndexedSeq[(Int, String)] = Vector((2,two), (1,one), (3,three))
a.toIterable        # Iterable[(Int, String)]             = Map(2 -> two, 1 -> one, 3 -> three)
a.toIterator        # Iterator[(Int, String)]             = non-empty iterator
a.toList            # List[(Int, String)]                 = List((2,two), (1,one), (3,three))
a.toSeq             # Seq[(Int, String)]                  = ArrayBuffer((2,two), (1,one), (3,three))
a.toSet             # immutable.Set[(Int, String)]        = Set((2,two), (1,one), (3,three))
a.toStream          # immutable.Stream[(Int, String)]     = Stream((2,two), ?)
a.toString          # String                              = Map(2 -> two, 1 -> one, 3 -> three)
a.toTraversable     # Traversable[(Int, String)]          = Map(2 -> two, 1 -> one, 3 -> three)
a.toVector          # Vector[(Int, String)]               = Vector((2,two), (1,one), (3,three))

a.updated(1, "ONE!")     # Map(1 -> ONE!, 2 -> two, 3 -> three)

a.zip(Seq(10,20,30))     # Map((1,one) -> 10, (2,two) -> 20, (3,three) -> 30)
a.zip(Map(
    "a" -> "aa",
    "b" -> "bee"
))
# result: mutable.Map[(Int, String),(String, String)] = Map((1,one) -> (a,aa), (2,two) -> (b,bee))

a.zipWithIndex           # Map((1,one) -> 0, (2,two) -> 1, (3,three) -> 2)
Back to top

Informational and mathematical methods

Informational and mathematical methods let you obtain information about a collection and the contents of the collection.

Method Returns
canEqual(a) True if the map “can equal” the parameter a of base type Any (should be defined by user-defined subclasses)
contains(k) True if the map contains the key k
count(p) The number of elements in the map for which the predicate is true
exists(p) True if the predicate returns true for at least one element in the map
find(p) The first element that matches the predicate p, returned as an Option
forall(p) True if the predicate p is true for all elements in the map
hasDefiniteSize True if the map has a finite size
head The first element of the map (which can/will vary depending on the map type); can throw NoSuchElementException
headOption The first element of the map returned as an Option (which can/will vary depending on the map type)
isDefinedAt(k) True if the map contains the index k
isEmpty True if the map contains no elements
last The last element of the map (which can/will vary depending on the map type); can throw NoSuchElementException
lastOption The last element of the map returned as an Option (which can/will vary depending on the map type)
max The largest element in the map
min The smallest element in the map
nonEmpty True if the map is not empty (i.e., if it contains 1 or more elements)
product The result of multiplying the elements in the map
size The number of elements in the map
sum The sum of the elements in the map
fold(s)(o) “Fold” the elements of the map using the binary operator o, using an initial seed s (see also reduce)
foldLeft(s)(o) “Fold” the elements of the map using the binary operator o, using an initial seed s, going from left to right (see also reduceLeft)
foldRight(s)(o) “Fold” the elements of the map using the binary operator o, using an initial seed s, going from right to left (see also reduceRight)
reduce “Reduce” the elements of the map using the binary operator o
reduceLeft “Reduce” the elements of the map using the binary operator o, going from left to right
reduceRight “Reduce” the elements of the map using the binary operator o, going from right to left

Examples

Examples:

val a = Map(
    1 -> "one",
    2 -> "two",
    3 -> "three"
)

# `canEqual` should be defined by user-defined subclasses
a.canEqual("foo")               # true
a.canEqual(1)                   # true
a.canEqual(null)                # true

a.contains(1)                   # true
a.contains(0)                   # false

a.count(t => t._1 > 1)          # 2
a.count{case (k,v) => k > 1}    # 2

a.exists(t => t._1 > 1)         # true
a.exists{case (k,v) => k > 1}   # true

a.find(t => t._1 > 1)           # Some((2,two))
a.find{case (k,v) => k > 1}     # Some((2,two))

a.forall(t => t._1 > 0)         # true
a.forall(t => t._1 > 33)        # false
a.forall{case (k,v) => k > 0}   # true

a.hasDefiniteSize               # true
a.head                          # (1,one)
a.headOption                    # Some((1,one))
a.isDefinedAt(0)                # 0
a.isDefinedAt(1)                # 1
a.isEmpty                       # false
a.last                          # (3,three)
a.lastOption                    # Some((3,three))
max                             # (3,three)
min                             # (1,one)
a.nonEmpty                      # true
product TODO
a.size                          # 3
a.sum

# foldLeft expects your algorithm to return a type that matches the map key type
a.foldLeft(0) {
   case(i, (k,v)) => {println(s"i = $i, k = $k"); k+i }
}
# result:
i = 0, k = 2
i = 2, k = 1
i = 3, k = 3
res0: Int = 6

a.foldLeft(0) {
    case(acc, (k,v)) => {
        val result = k + acc
        println(s"acc = $acc, k = $k, v = $v, result = $result")
        result
    }
}
acc = 0, k = 2, v = two, result = 2
acc = 2, k = 1, v = one, result = 3
acc = 3, k = 3, v = three, result = 6
res1: Int = 6
Back to top

Grouping methods

These methods generally let you create multiple groups from a collection.

Method Returns
groupBy(f) A map of collections created by the function f
grouped Breaks the map into fixed-size iterable collections
partition(p) Two traversable collections created by the predicate p
sliding(i,s) Group elements into fixed size blocks by passing a sliding window of size i and step s over them
span(p) A tuple of two collections; the first created by sequence.takeWhile(p), and the second created by sequence.dropWhile(p)
splitAt(i) A tuple of two maps by splitting the sequence at index i
unzip(asPair) TODO Two collections of the first and second half of each pair, using the implicit parameter asPair
unzip3 TODO
a.groupBy(t => t._1 > 99)
// Map[Boolean,Map[Int,String]] = Map(false->Map(1->one, 2->two, 3->three))

a.groupBy{case (k,v) => k > 1}
// Map[Boolean,Map[Int,String]] = Map(false->Map(1->one), true->Map(2->two, 3->three))

a.grouped(2)
// Iterator[Map[Int,String]] = non-empty iterator

a.partition(t => t._1 > 99)
// Map[Int,String], Map[Int,String]) = (Map(), Map(1->one, 2->two, 3->three))

a.sliding(2)
// Iterator[Map[Int,String]] = non-empty iterator

scala> a.sliding(1,1)
// Iterator[Map[Int,String]] = non-empty iterator

a.span(t => t._1 > 99)
// (Map[Int,String], Map[Int,String]) = (Map(),Map(1->one, 2->two, 3->three))

a.splitAt(1)
// (Map[Int,String], Map[Int,String]) = (Map(1->one), Map(2->two, 3->three))

a.splitAt(2)
(Map[Int,String], Map[Int,String]) = (Map(1->one, 2->two),Map(3->three))
Back to top

More Map implementations (sorted, linked, hash, weak)

The basic (common) Scala map classes and traits:

Class or Trait Description
collection.immutable.Map The default, general-purpose immutable map you get if you don’t import anything.
collection.mutable.Map A mutable version of the basic map.
collection.mutable.LinkedHashMap “All methods that traverse the elements will visit the elements in their insertion order.”
collection.immutable.ListMap
collection.mutable.ListMap
Per the Scaladoc, “implements immutable maps using a list-based data structure.” As shown in the examples, elements that are added are prepended to the head of the list.
collection.SortedMap Keys of the map are returned in sorted order. Therefore, all traversal methods (such as foreach) return keys in that order.

More Map types:

Class or Trait Description
collection.immutable.HashMap From the Scaladoc, “implements immutable maps using a hash trie.”
collection.mutable.ObservableMap From the Scaladoc: “This class is typically used as a mixin. It adds a subscription mechanism to the Map class into which this abstract class is mixed in.”
collection.mutable.MultiMap From the Scaladoc: “A trait for mutable maps with multiple values assigned to a key.”
collection.mutable.SynchronizedMap From the Scaladoc: This trait “should be used as a mixin. It synchronizes the map functions of the class into which it is mixed in.”
collection.immutable.TreeMap From the Scaladoc: “implements immutable maps using a tree.”
collection.mutable.WeakHashMap A wrapper around java.util.WeakHashMap, “a map entry is removed if the key is no longer strongly referenced.”

But wait, there’s still more (concurrent/parallel):

  • collection.parallel.immutable.ParHashMap
  • collection.parallel.mutable.ParHashMap
  • collection.concurrent.TrieMap

Sorted Map

Keys are stored in sorted order:

import scala.collection.SortedMap
val grades = SortedMap(
    "Kim" -> 90,
    "Al" -> 85, 
    "Melissa" -> 95,
    "Emily" -> 91,
    "Hannah" -> 92
)

// REPL
scala> grades.foreach(println)
(Al,85)
(Emily,91)
(Hannah,92)
(Kim,90)
(Melissa,95)

Maps that remember the insertion order of elements

If you want a map that remembers the insertion order of its elements, use a LinkedHashMap or ListMap. Scala only has a mutable LinkedHashMap, and it returns its elements in the order you inserted them:

import scala.collection.mutable.LinkedHashMap
val states = LinkedHashMap("IL" -> "Illinois")
states += ("KY" -> "Kentucky")
states += ("TX" -> "Texas")

//REPL
scala> states.foreach(println)
(IL,Illinois)
(KY,Kentucky)
(TX,Texas)

Scala has both mutable and immutable ListMap classes. They return elements in the opposite order in which you inserted them, as though each insert was at the head of the map (like a List):

import scala.collection.mutable.ListMap
val states = ListMap("IL" -> "Illinois")
states += ("KY" -> "Kentucky")
states += ("TX" -> "Texas")

//REPL
scala> states.foreach(println)
(TX,Texas)
(IL,Illinois)
(KY,Kentucky)
Back to top

How to convert Java Map to Scala Map

Convert a Java Map to a Scala Map using Scala’s JavaConverters object:

// import what you need
import java.util._
import scala.collection.JavaConverters._

// create and populate a java map
val jMap = new HashMap[String, String]()
jMap.put("first_name", "Alvin")
jMap.put("last_name",  "Alexander")

// convert the java map to a scala map
val sMap = jMap.asScala

Can also convert Java Properties to a Scala Map:

import java.util._
val javaProps = new Properties
javaProps.put("first_name", "Adam")
javaProps.put("last_name", "Scott")

import scala.collection.JavaConverters._
val scalaProps = p.asScala

What that looks like in the REPL:

scala> val javaProps = new Properties
javaProps: java.util.Properties = {}

scala> javaProps.put("first_name", "Adam")
res2: Object = null

scala> javaProps.put("last_name", "Scott")
res3: Object = null

scala> val scalaProps = p.asScala
scalaProps: scala.collection.mutable.Map[String,String] = 
    Map(last_name -> Scott, first_name -> Adam)

More details:

Back to top

Scala Map class summary

I hope these Scala Map class examples have been helpful. All of these examples will work with other immutable map classes that are subclasses of Map, and the mutable Map class will have other methods in addition to the methods shown here.

Back to top

The Scala Cookbook

This tutorial is sponsored by the Scala Cookbook, which I wrote for O’Reilly, and which you can find on Amazon.com:

I hope it has been helpful. All the best, Al.

Back to top

Add new comment

Anonymous format

  • Allowed HTML tags: <em> <strong> <cite> <code> <ul type> <ol start type> <li> <pre>
  • Lines and paragraphs break automatically.