Golang Map Examples

This Go tutorial uses maps to provide lookups from keys to values. It uses strings and ints in example programs.

Maps. Often we must find values from keys.

A bird is blue. We can map the string "bird" to the string "blue." This improves performance and enforces uniqueness of keys.

 

 

A solution. The map built-in provides a way to declare, with composite literal syntax, an entire table. And with a simple access we can find a value from a key (or test if a value exists).

 

 

First example. We first create a map that has string keys and string values. The key type is specified in the brackets after the "map" keyword. The value type comes afterward.

 

Syntax: We show the composite literal syntax in the "colors" table. We map the string "cat" to "black."

Access: We retrieve a value from the map at the key "snake." The string "green" is returned.

Based on:

Golang 1.4

Golang program that uses map

package main

import "fmt"

func main() {
    // Map animal names to color strings.
    // ... Create a map with composite literal syntax.
    colors := map[string]string{
	"bird":  "blue",
	"snake": "green",
	"cat":   "black",
    }

    // Get color of snake.
    c := colors["snake"]

    // Display string.
    fmt.Println(c)
}

Output

green

Add with assignment. An empty map can be created. We can then add keys and associated values imperatively (with statements) in separate lines.

Tip: In this way we can add data to a map in a loop. We must specify an empty initialization of the map.

Len: The len operator, also used on arrays and slices, can be used on a map. It counts keys (which is the same as the count of values).

Golang program that adds keys with assignments

package main

import "fmt"

func main() {
    // Create an empty map.
    names := map[int]string{}
    // Add three pairs to the map in separate statements.
    names[990] = "file.txt"
    names[1009] = "data.xls"
    names[1209] = "image.jpg"

    // There are three pairs in the map.
    fmt.Println(len(names))
}

Output

3

Delete. We can add keys to a map by assigning them. But to delete a key and its value, we must use the delete built-in: the pair is entirely erased.

Here: We add three entries to a map. The length is 3. We then delete one key and the length is reduced to 2.

Golang program that uses delete built-in

package main

import "fmt"

func main() {
    // Create an empty map and add three pairs to it.
    ids := map[string]int{}
    ids["steve"] = 10
    ids["mark"] = 20
    ids["adnan"] = 30
    fmt.Println(len(ids))

    // Delete one key from it.
    delete(ids, "steve")
    fmt.Println(len(ids))
}

Output

3
2

Loop over map. With the "for" and "range" keywords we can iterate over a map. We must assign variables to the two return values returned by the range expression.

Note: We can use a blank identifier (the underscore "_") to store the result of a key or value if it will not be used.

Golang program that uses for-loop on map

package main

import "fmt"

func main() {
    // Create a string to string map.
    animals := map[string]string{}
    animals["cat"] = "Mittens"
    animals["dog"] = "Spot"

    // Loop over the map.
    for key, value := range animals {
	fmt.Println(key, "=", value)
    }
}

Output

cat = Mittens
dog = Spot

Ok syntax. A key lookup in a map returns two values: the value (if found) and a value that indicates success or failure. We often name this "success" value "ok."

Ok: In the if-statements, the ok variable is set and then tested. If true, the inner blocks are reached.

Tip: With the "comma ok" idiom, we can test for existence and store the lookup result in one statement.

Golang program that uses map, ok syntax

package main

import (
    "fmt"
)

func main() {
    meds := map[string]int{
	"Ativan": 15,
	"Xanax": 20,
	"Klonopin": 30,
    }

    // The ok variable is set to true.
    if dosage, ok := meds["Xanax"]; ok {
	fmt.Println("Xanax", dosage)
    }

    // The ok variable is set to false.
    // ... The string does not exist in the map.
    if dosage, ok := meds["Atenolol"]; ok {
	fmt.Println("Atenolol", dosage)
    }
}

Output

Xanax 20

Performance, map versus slice. A map accelerates lookups: it uses a special hash code to guide a search. Here I compare a map search to a slice search.

And: For both the map and the slice, we try to locate the index of the value "bird." The map has indexes as its values.

Result: The map has a clear performance advantage in this case. For larger amounts of data, this will become even greater.

Golang program that benchmarks map, slice

package main

import (
    "fmt"
    "time"
)

func main() {
    lookup := map[string]int{
	"cat":  0,
	"dog":  1,
	"fish": 2,
	"bird": 3}
    values := []string{"cat", "dog", "fish", "bird"}
    temp := 0

    t0 := time.Now()

    // Version 1: search map with lookup.
    for i := 0; i < 10000000; i++ {
	v, ok := lookup["bird"]
	if ok {
	    temp = v
	}
    }

    t1 := time.Now()

    // Version 2: search slice with for-loop.
    for i := 0; i < 10000000; i++ {
	for x := range(values) {
	    if values[x] == "bird" {
		temp = x
		break
	    }
	}
    }

    t2 := time.Now()
    // Benchmark results.
    fmt.Println(temp)
    fmt.Println(t1.Sub(t0))
    fmt.Println(t2.Sub(t1))
}

Results

3
176.1265ms   map lookup
212.1489ms   slice, for-loop

A summary. We used the map built-in to link keys to values. We tested that keys exist and we retrieved the appropriate values. A map provides a clear performance win.