Maps
A map is an unordered collection of key/value pairs. Because maps are unordered, there’s no way to predict the order in which the key/value pairs will be returned.
Internally, a map is a pointer to the runtime.hmap structure. This hash table contains a collection of buckets. When you’re storing, removing, or looking up a key/value pair, everything starts with selecting a bucket. This is performed by passing the key to the map’s hash function. The hash function generates an index that evenly distributes key/value pairs across all available buckets.
The strength of a map is its ability to retrieve data quickly based on the key. They do not have a capacity or a restriction on growth.
Keys
A map key can be a value from any built-in or struct type as long as the value can be used in an expression with the == operator. You cannot use:
- slices
- functions
- struct types that contain slices
Creating a map
There are multiple options to create a map:
- nil map. If you declare a nil map with the
varkeyword, then you have to usemaketo initialize it. - Rather than create a nil map, you can declare and initialize it in one expression with
make. - The idiomatic way to create a map is to initialize it with values.
func main() {
var people map[string]int // 1
people = make(map[string]int) // 1 map[]
initMap := make(map[string]int) // 2
initMap["Sally"] = 22 // map[Sally:22]
colors := map[string]string{ // 3 map[Orange:#e95a22 Red:#da1337]
"Red": "#da1337",
"Orange": "#e95a22",
}
}
Accessing maps
Access values in a map with the bracket notation:
- Bracket notation uses the format
<map-name>["<value>"]. - If the value does not exist, it returns nothing.
- Check if a map contains a key with the “comma-ok” idiom. This expression returns a value (
color) and a boolean (ok). The boolean istrueif the key exists in the map. - If the boolean is
true, do some work with the returned value
func main() {
colors := map[string]string{
"Red": "#da1337",
"Orange": "#e95a22",
"White": "#ffffff",
"Black": "#000000",
}
fmt.Println(colors["Orange"]) // 1 #e95a22
fmt.Println(colors["Blue"]) // 2
color, ok := colors["Red"] // 3
if ok { // 4
fmt.Println("Red value:", color) // Red value: #da1337
}
}
Here is the compact version:
if val, ok := mapname["blue"]; ok {
// ...
}
Some Go code uses the word exists or found in place of ok:
value, exists := colors["Blue"]
if exists {
fmt.Println(value)
}
for…range
Loop through a map with the for...range loop:
- You can access the keys and values the same way you access the index and value in a slice.
- Omit the values to return only the keys.
- You can’t omit the keys and return only the values. Instead, you have to create a slice, ignore the key with an underscore (
_), the append the values to the slice.
func main() {
colors := map[string]string{
"Red": "#da1337",
"Orange": "#e95a22",
"White": "#ffffff",
"Black": "#000000",
}
for k, v := range colors { // 1
fmt.Println(k, v)
}
for k := range colors { // 2
fmt.Println(k)
}
var vals []string // 3
for _, v := range colors {
vals = append(vals, v)
}
fmt.Println(vals)
}
Modifying elements
To modify a value, reassign the existing value with bracket notation. Here, we override the "Red" value with "not ascii":
func main() {
colors := map[string]string{
"Red": "#da1337",
"Orange": "#e95a22",
"White": "#ffffff",
"Black": "#000000",
}
colors["Red"] = "not ascii"
}
Deleting elements
Use the delete method to remove a key from the map:
deleteaccepts a map and the key you want to remove from the map.
func main() {
colors := map[string]string{
"Red": "#da1337",
"Orange": "#e95a22",
"White": "#ffffff",
"Black": "#000000",
}
for k, v := range colors { // Red: #da1337, Orange: #e95a22, White: #ffffff, Black: #000000,
fmt.Printf("%s: %s, ", k, v)
}
delete(colors, "White") // 1
for k, v := range colors { // Orange: #e95a22, Black: #000000, Red: #da1337
fmt.Printf("%s: %s, ", k, v)
}
}
Sorting maps
To sort a map, you have to put the keys into a slice, sort the slice, then access the map using the slice:
- Create a slice for the keys.
- Loop over the
keysslice, and append each key to the slice. - Sort the slice to put
keysin order. - Range over the
keysslice, printing the keys in order. You can access the keys in the map with bracket notation.
func main() {
people := map[string]int{
"Ricky": 34,
"Sally": 52,
"Cal": 9,
"Betty": 23,
}
var keys []string // 1
for k := range people { // 2
keys = append(keys, k)
}
sort.Strings(keys) // 3
for _, key := range keys { // 4
fmt.Println(key, people[key])
}
}
Passing to functions
Functions do not make copies of the map. Any changes made to the map by the function are reflected by all references to the map:
removeColorremoves keys from the specified map. Pass the map as<name> map[type]type- Create a map of colors and color hex codes.
- Call the function to remove the specified key.
- Loop over the map to display all the colors in the map.
func removeColor(colors map[string]string, key string) {
delete(colors, key)
}
func main() {
colors := map[string]string{
"AliceBlue": "#f0f8ff",
"Coral": "#ff7F50",
"DarkGray": "#a9a9a9",
"ForestGreen": "#228b22",
}
removeColor(colors, "Coral")
for key, value := range colors {
fmt.Printf("Key: %s Value: %s\n", key, value)
}
}