Skip to main content

Maps in Go

·9 mins
Table of Contents

Maps are a powerful data structure, providing a way to store and retrieve data based on keys.

They are widely used in various applications, from web development to data processing, and are an essential part of any Go programmer’s toolkit.

In this article, we’ll take a closer look at how maps work in Go and how you can use them to solve real-world problems. So buckle up and let’s start exploring the world of maps in Go!

Add an item to a map>

Add an item to a map #

To add an item to a map in Go, you can use the assignment operator :=:

m := map[int]string{0: "zero", 1: "one", 2: "two"}
mymMap[3] = "three"
fmt.Println(m)

Result:

map[0:zero 2:two 3:three]

In this example, a map m is created with some key-value pairs. Then we add an item to the map with the key 3 and the value three.

Delete a key in a map>

Delete a key in a map #

To delete a key from a map in Go, you can use the delete function:

m := map[int]string{0: "zero", 1: "one", 2: "two"}
delete(m, 1)
fmt.Println(m)

Result:

map[0:zero 2:two]

In this example, the delete function is used to remove the key 1 and its associated value from the m map.

Note: Deleting a key that is not in the map has no effect and does not produce an error.

Check if a map contains a key>

Check if a map contains a key #

To check if a map contains a key in Go, you can try the following example:

m := map[int]string{0: "zero", 1: "one", 2: "two"}
v, exists := m[2]
if exists {
	fmt.Println(v)
} else {
	fmt.Println(exists)
}

Result:

two

If m[2] is changed to m[3] the result will be:

false

v is the value associated with the key in the map, and exists is a boolean that indicates whether the key is present in the map.

If the key is in the map, exists will be true and v will be set to the value associated with the key.

If the key is not in the map, exists will be false and value will be the zero value of the type of the values stored in the map.

Iterating over the keys of a map>

Iterating over the keys of a map #

To iterate over the keys of a map in Go, you can use a for loop to iterate over the key-value pairs in the map. Here is an example:

m := map[int]string{0: "zero", 1: "one", 2: "two"}
for key := range m {
	fmt.Println(key)
}

Result:

0
1
2

In this example, the for loop will iterate over all the key-value pairs in m, and the keys will be printed one by one.

In Go, the built-in map type does not provide a guaranteed order for its keys. If you need an ordered map check the Ordered map section of this article.

Getting a slice of keys from a map>

Getting a slice of keys from a map #

To get a slice of keys from a map in Go, you can use a for loop to iterate over the key-value pairs in the map and append the keys to a slice:

m := map[int]string{0: "zero", 1: "one", 2: "two"}
keys := make([]int, 0, len(m))
for key := range m {
	keys = append(keys, key)
}
fmt.Println(keys)

Result:

[0 1 2]

In this example, keys will be a slice of strings containing the keys from m.

A note about the make function>

A note about the make function #

The make function is used to create slices, maps, and channels in Go.

In this example make is used to create an empty slice with capacity equal to the number of elements in the map, to avoid repeated resizing of the slice as keys are appended.

The first argument to make is the type of the object you want to create, the second argument is the length, and the third (optional) argument is the capacity.

In this case, the slice keys is created with a length of 0 and a capacity of len(m) because the intention is to fill the slice with the keys from the m map.

To be efficient in Go, it’s important to minimize memory allocations.

Sort a map>

Sort a map #

If you need the keys to be processed in a specific order, you can sort the slice of keys first and then iterate over the sorted keys:

m := map[int]string{0: "zero", 1: "one", 2: "two"}
keys := make([]int, 0, len(m))

for key := range m {
	keys = append(keys, key)
}

// Replace this with your type: sort.Strings for strings
sort.Ints(keys)

for _, key := range keys {
	fmt.Printf("%v: %v\n", key, m[key])
}

Result:

0: zero
1: one
2: two

In this example, the keys slice is created and filled with the keys from the m map.

Then the sort.Ints function is used to sort the keys slice.

Finally, a loop is used to iterate over the sorted keys slice and print the key-value pairs from the m map.

Ordered map>

Ordered map #

In Go, the built-in map type does not provide a guaranteed order for its keys.

However, if you need an ordered map you can use go-ordered-map which provides an implementation of an ordered map in Go, with functions for inserting, deleting, and accessing items in order.

import "github.com/elliotchance/orderedmap/v2"

func main() {
	m := orderedmap.NewOrderedMap[int, string]()

	m.Set(0, "zero")
	m.Set(1, "one")
	m.Set(2, "two")

	m.Delete(0)

	for _, key := range m.Keys() {
		value, _ := m.Get(key)
		fmt.Println(key, value)
	}
}

Result:

0 zero
2 two
Convert a map to Json>

Convert a map to Json #

To convert a Go map to a JSON string, you can use the encoding/json package:

m := map[int]string{0: "zero", 1: "one", 2: "two"}
jsonBytes, err := json.Marshal(m)
if err != nil {
	log.Fatalln(err)
}
fmt.Println(string(jsonBytes))

Result:

{"0":"zero","1":"one","2":"two"}

In this example, the json.Marshal function is used to convert the m map to a JSON string.

The jsonBytes variable will contain the JSON string representation of the map, which can be printed or written to a file as needed.

If an error occurs during the conversion, the err variable will be set to a non-nil value and the error message will be printed.

Compare two maps>

Compare two maps #

To compare if two maps are equal in Go, you can use the reflect package in order to compare the values stored in them:

m1 := map[int]string{0: "zero", 1: "one", 2: "two"}
m2 := map[int]string{0: "zero", 1: "one", 2: "two"}

if reflect.DeepEqual(m1, m2) {
	fmt.Println("m1 and m2 are equal")
} else {
	fmt.Println("m1 and m2 are not equal")
}

Result:

m1 and m2 are equal

The reflect.DeepEqual function is used to compare the values stored in maps, and to determine if they are equal or not.

If the values are equal, reflect.DeepEqual returns true, and if the values are not equal, it returns false.

Clear a map>

Clear a map #

To clear a map in Go, you can simply assign a new empty map to the existing map variable:

m := map[int]string{0: "zero", 1: "one", 2: "two"}
	
fmt.Println("Before clearing:", m)

// Clear the map
m = make(map[int]string)

fmt.Println("After clearing:", m)

Result:

Before clearing: map[0:zero 1:one 2:two]
After clearing: map[]

In this example, a map m is created and filled with key-value pairs.

Then the map is cleared by assigning a new empty map created with make(map[int]string) to the m variable.

Slice to Map>

Slice to Map #

You can convert a slice to a map in Go by iterating over the slice and adding each element as a key-value pair in the map:

list := []int{0, 1, 2, 3}

m := make(map[int]bool)
for _, value := range list {
	m[value] = true


fmt.Println("Slice:", list)
fmt.Println("Map:", m)

Result:

Slice: [0 1 2 3]
Map: map[0:true 1:true 2:true 3:true]

In this example, a slice m is created with some string values.

Then the slice is converted to a map by using a for loop to iterate over the slice and adding each element as a key in the map with a value of true.

The make function is used to create a new map with map[string]bool.

Reverse a map>

Reverse a map #

The purpose of reversing a map is to switch the keys and the values.

As an example a map of integer keys and string values will be reversed to a map of string keys and integer values.

Why is this useful? Take for example a map of IDs and names, we can access the names with the IDs, but what if we want to access the IDs with the names? We would have to iterate it each time we want to make a search, which is not efficient, what we can do instead is iterate it once.

Let’s see two examples:

One fixed type>

One fixed type #

m := map[int]string{0: "zero", 1: "one", 2: "two"}

rMap := make(map[string]int)
for key, value := range m {
	rMap[value] = key
}

fmt.Println("Original Map:", m)
fmt.Println("Reversed Map:", rMap)

Result:

Original Map: map[0:zero 1:one 2:two]
Reversed Map: map[one:1 two:2 zero:0]

This code shows how to reverse a map in Go by creating a new map with the keys and values swapped, the new map will have the same values as the original map, but with the keys and values switched.

Here’s what it does it:

A map m is created with some key-value pairs. Then the map is reversed by using a for loop to iterate over the original map, swapping the keys and values for each iteration.

The make function is used to create a new map with map[string]int.

Multiple types>

Multiple types #

func main() {
	m := map[int]string{0: "zero", 1: "one", 2: "two"}
	rMap := reverseMap(m).(map[string]int)

	fmt.Println("Original Map:", m)
	fmt.Println("Reversed Map:", rMap)
}

func reverseMap(m any) any {
	v := reflect.ValueOf(m)
	if v.Kind() != reflect.Map {
		return nil
	}

	mType := reflect.MapOf(v.Type().Elem(), v.Type().Key())
	toReturn := reflect.MakeMap(mType)

	for _, k := range v.MapKeys() {
		toReturn.SetMapIndex(v.MapIndex(k), k)
	}

	return toReturn.Interface()
}

Result:

Original Map: map[0:zero 1:one 2:two]
Reversed Map: map[one:1 two:2 zero:0]

In this example, the reverseMap function takes a map with keys and values of type any as an argument, and returns a reversed map with the same keys and values. This allows the function to be used with maps of different types.

The for loop inside the reverseMap function is used to iterate over the original map, swapping the keys and values for each iteration.

The main function creates a map m with some key-value pairs, and calls the reverseMap function to get the reversed map.

Note: In the example we have to type again the result in order to not get an any type:

m2 := reverseMap(m).(map[string]int)

Usage of reflect is often dangerous, and you need to be sure you know what you’re doing if the map contains nested objects or other shenanigans