Iterating over a Golang map
See also Iterators in Go for information about the new “range over func” experiment.
This is part 5 of a series on Go maps:
- Declaring and initializing maps
- Map types in Go
- Storing and retrieving map values
- Finding whether a Go map key exists
- Iterating over a Go map
map[string]interface{}
in Go- Frequently asked questions about Go maps
How do you iterate over Golang maps? How do you print a map? How do you write a for
loop that executes for each key and value in a map? What is the iteration order of Go maps? In Part 4 of this series, we saw how to query a specific key in a map, but how can you get all the keys?
Since a Go map is fundamentally a collection of things, it makes sense that we would want to use it with for
loops, where we do the same operation with every key-value pair in the map.
How to print a Golang map
Before we look at loops, let’s consider one of the simplest things we might want to do with a map in Go: print it out! That’s easy, as you might expect; we can use the all-purpose fmt
library:
:= map[string]float64{
menu "eggs": 1.75,
"bacon": 3.22,
"sausage": 1.89,
}
.Println(menu) fmt
The result:
map[bacon:3.22 eggs:1.75 sausage:1.89]
This is a quick way to see the contents of a map, especially if you’re trying to debug a program, but it’s not a particularly delightful format, and we have no control over it. For more flexible printing, we can iterate over the map.
How to iterate over a map
To iterate over a map is to read each successive key-value pair in a loop. We can do this using the range
operator. For example, to print out our diner menu we might write:
.Println("Gopher's Diner Breakfast Menu")
fmtfor dish, price := range menu {
.Println(dish, price)
fmt}
range
on a map returns two values (received as the variables dish
and price
in our example), which are the key and value respectively. Each time round the loop, dish
is set to the next key, and price
is set to the corresponding value.
The results:
Gopher's Diner Breakfast Menu
eggs 1.75
bacon 3.22
sausage 1.89
Delicious!
Listing the keys in a map
Suppose we weren’t bothered about the prices for the moment, and we simply wanted to make a list of dishes, perhaps for when we go shopping for ingredients. When we don’t want the second value returned by range
, we simply don’t supply a variable to receive it:
for dish := range menu {
.Printf("Remember to buy %s\n", dish)
fmt}
Result:
Remember to buy eggs
Remember to buy bacon
Remember to buy sausage
Getting only the values in a map
When we only want the second value from range
, we can supply a placeholder to receive the first value: the blank identifier “_
”:
// Just give me all the bacon and eggs you have.
var total float64
for _, price := range menu {
+= price
total }
.Printf("An 'everything breakfast' will cost you %.02f\n", total) fmt
Result:
An 'everything breakfast' will cost you 6.86
Map iteration order
An interesting question to ask about maps in Go is “what is the iteration order of a map?” In other words, when we loop over successive keys with a for
statement, what does ‘successive’ mean?
You might think that the iteration order of a map is simply the order that you defined the keys in. For example, we listed eggs
first in the map literal, so shouldn’t we see eggs
as the first key when we loop over it?
In fact, the Go spec says that the iteration order over maps is not specified. That is to say, you should not expect the map keys to appear in any particular order.
This makes sense when you understand how Go maps are implemented, but we needn’t worry about the details here. Just know that you can’t rely on iterating over a map in a specific order.
The iteration order of maps is also unstable, meaning that it won’t necessarily be the same every time you run the program. Beware of writing tests which depend on map keys appearing in a certain order: this is a flaky test which can pass one time, and fail the next!
Cool fact: when you print a map in Go, it’s always in key order. This is to make testing easier, but don’t rely on this. You shouldn’t think of the map as having any inherent ordering.
Ordering map keys
So how do you iterate over map keys in a certain order? The only way is to store the keys yourself, as a slice, and then order them the way you want:
var dishes []string
for dish := range menu {
= append(dishes, dish)
dishes }
.Strings(dishes)
sort.Println("In alphabetical order:")
fmtfor _, dish := range dishes {
.Println(dish, menu[dish])
fmt}
The result:
In alphabetical order:
bacon 3.22
eggs 1.75
sausage 1.89
Next
Assuming you’re not too hungry to continue, you can go on to the next tutorial in this series, which is all about the very useful map[string]interface{}
type.
Gopher image by egonelbre