How to make and use maps in Golang
Maps are a popular data structure in many programming contexts thanks to their efficiency and speed. But, in Go, some unique features make maps especially useful.
In computer programming, a map is a data structure that stores key-value pairs. Each key is paired with a corresponding value, which is retrieved by referencing the key.
Programmers often choose to work with maps for their computational efficiency. Maps -- also called hash tables, associative arrays, symbol tables or dictionaries -- enable quicker insets, retrievals and removals compared with arrays.
Maps accomplish this using a hashing function paired with an array made up of arrays of key-value pairs. When a key is added to a map, the hashing function returns an integer based on the key. To find the key again, the hashing function must return the same integer every time.
To insert a new key, the integer returned from the hashing function is used to place the key-value pair in one of the aforementioned arrays, which functions as a bucket of key-value pairs. Upon looking up a key, instead of searching through the entire map, the hashing function limits the search space to a specific bucket containing a subset of keys to iterate through.
At a high level, it's easy to see how maps can save time and computations over arrays, which require searching the entire array to find an item. To understand the details of how maps work, take a look at some examples of operations on maps in Go, also known as Golang.
Assigning and overwriting values in Go maps
The map shown in Figure 1 is named models and stores different models from car manufacturers. A map is not the best choice of structure for every type of data, but in this case, it is ideal. Because each manufacturer has a set number of models, there is a clear pairing between each auto manufacturer and the models it manufactures. Maps are designed with this type of key-value relationship in mind.
The code in Figure 1 creates a map on line 6, specifying that the keys are of the type string and the values are arrays of strings, indicated as string. On line 8, an array of three items is assigned to the key "Ford". But, in the final output, the key "Ford" is associated with an array of only one item.
To understand this result, remember that keys in Go maps must be unique. Because there is only one value for each key, assigning a value to an existing key overwrites the existing value. Consequently, in the final output, the value of the key "Ford" is an array that contains only the string "Mustang Mach-E" -- not the other values that were previously assigned to the key "Ford".
Modifying existing values in Go maps
Figure 2 shows an example of modifying an existing value in a map rather than overwriting it.
Line 12 references the key "Ford" instead of reassigning the value completely, which would overwrite the old value. Referencing the key returns the previously assigned value, and a new item is appended to the existing array.
Taking advantage of zero values in Go maps
Of course, associating unique keys with values is just one small part of what makes maps so useful. In Go, maps have a convenient feature where a key returns a zero value when no value is set for that key. Try that in Python, and you get a KeyError exception.
In Figure 3, line 12 sets the key "Subaru" by appending the string "Forester" to the result of getting the values already stored under the key "Subaru". In this case, no value is set for the key, so Go sets the initial value of the array to zero. Running the operation returns an empty array and appends the string "Forester" to that array.
Without Go's ability to return zero values, this program would first need to check whether a key was already set and then reference the key again to get the existing values to combine with the newly added string. Zero values in Go maps make for cleaner code that contains fewer steps and has a more intuitive flow.
Understanding order in Go maps
One important note about Go maps is that key-value pairs are not ordered. This means that the map's order can change from iteration to iteration, as shown in Figure 4. The example shows the results of running a program to print the map multiple times, but even if the program contained two separate for loops, their order of execution would not be guaranteed.
Third-party packages are available for making ordered maps in Go. Alternatively, programmers can sort maps using Go's sort package. But, in most cases, a standard unordered map does the job, as many programs and functions that use maps don't rely on the order of their key-value pairs.
For solutions requiring more complex data structures than arrays, linked lists or binary trees, maps are often a good fit. In Golang, maps have unique features that support good code design and make development easier -- but there are also some interesting gotchas compared with other languages' support of maps.