Map. In Scala 3.3, a map is the core dictionary type. We link values from keys. Usually we have Strings and Ints, but any type can be used.
Immutable notes. Scala maps are immutable—we cannot modify them once created. We can perform lookups, and loop over maps with foreach.
Initial example. Here we build a String map—it has String keys and Int values. We initialize it with just two pairs. Map is immutable so a new map would be needed to add elements.
Info To get a value from a key in the "colors" map, we access the colors like a function. We pass the key as the argument.
object Program {
def main(args: Array[String]): Unit = {
// Use simple map initialization syntax.
val weights = Map("cat" -> 10, "elephant" -> 200000)
// Look up animal weights.
val weight = weights("elephant")
println(weight)
}
}200000
Another example. We can initialize a Map with a different syntax based on a list of pairs. Here we use a String to String map. We look up two animal Strings.
object Program {
def main(args: Array[String]): Unit = {
// Create map of animals to colors.// ... Has string keys and string values.
val colors = Map(("bird", "blue"), ("fox", "red"))
// Get value for this key.
val result1 = colors("bird")
println(result1)
val result2 = colors("fox")
println(result2)
}
}blue
red
Add. A Map is immutable so we cannot add an element to an existing map. But we can add a key-value pair to a new, copied map. Here we add a zebra in a new map creation statement.
object Program {
def main(args: Array[String]): Unit = {
// Create an immutable map.
val zoo = Map("frog" -> 1, "lion" -> 1)
// Add a pair to the map.// ... This creates a new map.
val all = zoo + ("zebra" -> 1)
println(all)
}
}Map(frog -> 1, lion -> 1, zebra -> 1)
Keys, values. Here we create a map with String keys and Int values. We then access the keys and values properties to get collections of those elements.
Note We use the foreach function on the keys collection (which is an iterable) and use println on each key.
Also Here we use an imperative for-loop to call println on each value in the Map.
object Program {
def main(args: Array[String]): Unit = {
// Create map of String keys and Int values.
val ids = Map(("abc", 10), ("def", 20))
// Use foreach function to print each key.
ids.keys.foreach(println(_))
// Use for-loop to iterate over all values.
for (value <- ids.values) {
println(value)
}
}
}abc
def
10
20
Get, getOrElse. With get, an option is returned. If the value exists in the Map, isDefined will return true on that option. We can then call get() on the option.
Note Get() returns an option, not the value type of the Map. We must always test the option.
Note 2 GetOrElse() lets us provide a default value that is returned if the key does not exist in the Map. Here we use 0 as a default.
object Program {
def main(args: Array[String]): Unit = {
// Create a String, Int map.
val sizes = Map(("Medium", 2), ("Large", 4))
// This key does not exist, so the option is not defined.
val result1 = sizes.get("Small")
if (!result1.isDefined) {
println("Not defined")
}
// This key exists.// ... Get and print the option's internal value.
val result2 = sizes.get("Large")
if (result2.isDefined) {
println(result2)
val number = result2.get
println(number)
}
// Use a default value if the key does not exist.
val result3 = sizes.getOrElse("Small", 0)
if (result3 == 0) {
println("Zero, else value")
}
}
}Not defined
Some(4)
4
Zero, else value
Equals. With this method we test for structural equality of two maps. The order of the entries in the maps is not important. But the keys and values must be the same.
Here We find map1 and map2 are equal because their key-value pairs are the same. But map3 has a different value so it is not equal.
object Program {
def main(args: Array[String]): Unit = {
// Create three maps.// ... The first two are equal but have different orders.// The third one has different entries.
val map1 = Map((10, true), (20, false))
val map2 = Map((20, false), (10, true))
val map3 = Map((20, true), (10, true))
// These two maps are structurally equal.
if (map1.equals(map2)) {
println("Maps equal")
}
// Not equal.
if (!map1.equals(map3)) {
println("Maps not equal")
}
}
}Maps equal
Maps not equal
WithDefaultValue. A map can have a default value or function. We call withDefaultValue to specify a default value—in this program we use a default integer of -1.
So When we do a lookup on the map that does not find an existing key, the default value is returned.
Info WithDefaultValue() returns a default value based on a function. We can pass a lambda expression to it.
Here The map does not contain the key "bear" so the final look up in the program returns the value -1.
object Program {
def main(args: Array[String]): Unit = {
val animalMap = Map(("cat", 10), ("bird", 5))
// The default value is now negative 1.
val animalMapDefault = animalMap.withDefaultValue(-1);
// Use map with default.
val result1 = animalMapDefault("cat")
println(result1)
val result2 = animalMapDefault("bear")
println(result2)
}
}10
-1
Map performance. A Map is a good optimization. Here we have three elements "abc" and we store them in a Map and a List. We search for one element in the collections.
Version 1 In this version of the code we search the Map with a string argument. We repeat this operation in a for-loop.
Version 2 Here we try to find the element in a List. We use a for-loop to search. The operation is repeated many times.
Result Finding element "c" in the Map is faster than in the List. The fast lookup time helps this benchmark.
object Program {
def main(args: Array[String]): Unit = {
// Map and list used.
val lookup = Map(("a", 1), ("b", 1), ("c", 1))
val list = List("a", "b", "c")
var total = 0
val t1 = System.currentTimeMillis()
// Version 1: lookup element in a map.
for (i <- 0 until 10000000) {
val result = lookup("c")
total += result
}
val t2 = System.currentTimeMillis()
// Version 2: search for element in a list.
for (i <- 0 until 10000000) {
var result = 0
for (v <- list) {
if (v == "c") {
result = 1
}
}
total += result
}
val t3 = System.currentTimeMillis()
// Results.
println(total)
println(t2 - t1)
println(t3 - t2)
}
}20000000
77 ms, Map
140 ms, List
Summary. We use the Map type to associate keys with values. This provides fast, hashed lookups. Maps solve many performance problems, and can even simplify code by removing duplicates.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Dec 14, 2023 (edit).