Maps in Go
A map is Go’s built-in key-value data structure — like a dictionary (Python) or object (JavaScript). Keys are unique; values can repeat.
📖 Analogy: Think of a map like a phone book — you look up a name (key) to get a number (value). No two people share the same name entry.
1. Declaration & Initialization
// ✅ Using make — preferred for empty maps
m := make(map[string]int)
// ✅ Using literal — preferred when you have initial values
scores := map[string]int{
"Alice": 95,
"Bob": 87,
}
// ⚠️ Nil map — reading is safe, writing will PANIC
var m map[string]int
fmt.Println(m["key"]) // 0 — safe read
m["key"] = 1 // 💥 panic: assignment to nil mapRule: Always use
makeor a literal before writing to a map.
2. Core Operations
| Operation | Syntax | Notes |
|---|---|---|
| Insert / Update | m[key] = value | Creates if new, updates if exists |
| Read | val := m[key] | Returns zero value if key absent |
| Safe Read | val, ok := m[key] | ok is true only if key exists |
| Delete | delete(m, key) | No error if key doesn’t exist |
| Length | len(m) | Number of key-value pairs |
m := make(map[string]int)
m["Alice"] = 95 // insert
m["Alice"] = 97 // update
fmt.Println(m["Alice"]) // 97
fmt.Println(m["Bob"]) // 0 — key absent, returns zero value
val, ok := m["Bob"] // ⭐ always use this form to check existence
if !ok {
fmt.Println("Bob not found")
}
delete(m, "Alice")
fmt.Println(len(m)) // 03. Iteration
scores := map[string]int{"Alice": 95, "Bob": 87, "Carol": 91}
// Key + Value
for name, score := range scores {
fmt.Printf("%s: %d\n", name, score)
}
// Keys only
for name := range scores {
fmt.Println(name)
}⚠️ Iteration order is random every time. Never rely on order. If you need sorted output, extract keys into a slice and sort it.
// Sorted iteration
keys := make([]string, 0, len(scores))
for k := range scores {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
fmt.Printf("%s: %d\n", k, scores[k])
}4. Key Rules
| Allowed as Key? | Reason | |
|---|---|---|
string, int, bool | ✅ | Comparable |
struct (no slice/map fields) | ✅ | Comparable |
slice | ❌ | Not comparable |
map | ❌ | Not comparable |
float64 | ⚠️ Avoid | Precision issues can cause unexpected collisions |
5. Useful Patterns
Map of Slices — Grouping
groups := make(map[string][]string)
groups["fruits"] = append(groups["fruits"], "apple", "banana")
groups["vegs"] = append(groups["vegs"], "carrot")Set Simulation
// map[T]struct{} is more memory-efficient than map[T]bool
seen := make(map[string]struct{})
seen["alice"] = struct{}{}
if _, ok := seen["alice"]; ok {
fmt.Println("already visited")
}Copy a Map
original := map[string]int{"a": 1, "b": 2}
clone := make(map[string]int, len(original))
for k, v := range original {
clone[k] = v
}6. Competitive Programming Tips 🏆
Frequency Counter — most common pattern
// Count occurrences of each character/number
freq := make(map[int]int)
nums := []int{1, 2, 2, 3, 3, 3}
for _, n := range nums {
freq[n]++ // zero-value of int is 0, so this always works safely
}
// freq = {1:1, 2:2, 3:3}Two Sum Pattern
// Find two numbers that add up to target — O(n)
func twoSum(nums []int, target int) (int, int) {
seen := make(map[int]int) // value → index
for i, n := range nums {
if j, ok := seen[target-n]; ok {
return j, i
}
seen[n] = i
}
return -1, -1
}Anagram / Grouping by Sorted Key
// Group words that are anagrams of each other
func groupAnagrams(words []string) map[string][]string {
groups := make(map[string][]string)
for _, w := range words {
key := sortString(w) // "eat" → "aet"
groups[key] = append(groups[key], w)
}
return groups
}Memoization (Top-down DP)
memo := make(map[int]int)
func fib(n int) int {
if n <= 1 { return n }
if v, ok := memo[n]; ok {
return v
}
memo[n] = fib(n-1) + fib(n-2)
return memo[n]
}💡 CP Tip:
m[key]++is always safe even if the key doesn’t exist yet — Go returns the zero value (0for int,falsefor bool), so you never need to pre-initialize.
7. Common Mistakes ⚠️
| Mistake | Problem | Fix |
|---|---|---|
| Write to nil map | runtime panic | Use make or literal |
val := m[key] without ok check | silently gets zero value | Use val, ok := m[key] |
| Assume sorted iteration | non-deterministic output | Sort keys manually |
== to compare two maps | compile error | Loop and compare manually |
float64 as key | precision collision | Use string or int keys |
8. Interview Cheat Sheet
Q: What is the zero value of a map?
nil. A nil map can be read from safely (returns zero value) but writing to it causes a runtime panic.
Q: How do you check if a key exists?
val, ok := m[key]— use the two-value form.okistrueonly if the key is present.
Q: Is map a reference type?
Yes. Passing a map to a function does not copy the data — the function works on the original map.
Q: Why is iteration order random?
Go intentionally randomizes map iteration to prevent code from accidentally depending on order, since hash maps have no guaranteed order.
Q: What types can be used as map keys?
Any comparable type:
string,int,bool, structs with comparable fields. Slices and maps cannot be keys.
Q: What’s the difference between make(map[K]V) and map[K]V{}?
Both create an initialized, ready-to-use map.
makeis preferred for empty maps; literal{}syntax is preferred when you have initial values.
Quick Reference
| Operation | Syntax |
|---|---|
| Create (empty) | m := make(map[K]V) |
| Create (with values) | m := map[K]V{k: v} |
| Insert / Update | m[key] = value |
| Safe Read | val, ok := m[key] |
| Delete | delete(m, key) |
| Length | len(m) |
| Iterate | for k, v := range m {} |
| Increment counter | m[key]++ |