Skip to main content
โšก Calmops

Go Maps: Key-Value Pairs and Iteration

Go Maps: Key-Value Pairs and Iteration

Maps are Go’s built-in hash table implementation. They provide efficient key-value storage and retrieval.

Map Basics

Creating Maps

package main

import "fmt"

func main() {
    // Map literal
    ages := map[string]int{
        "Alice": 30,
        "Bob":   25,
        "Charlie": 35,
    }
    fmt.Println(ages)

    // Using make()
    scores := make(map[string]float64)
    scores["Alice"] = 95.5
    scores["Bob"] = 87.3
    fmt.Println(scores)

    // Empty map
    empty := make(map[string]string)
    fmt.Println(empty)
}

Accessing Values

package main

import "fmt"

func main() {
    person := map[string]string{
        "name": "Alice",
        "city": "New York",
    }

    // Get value
    name := person["name"]
    fmt.Println(name)  // Alice

    // Check if key exists
    city, ok := person["city"]
    if ok {
        fmt.Println(city)  // New York
    }

    // Non-existent key returns zero value
    country := person["country"]
    fmt.Println(country)  // "" (empty string)

    // Check with ok
    country, ok = person["country"]
    if !ok {
        fmt.Println("Country not found")
    }
}

Map Operations

Adding and Updating

package main

import "fmt"

func main() {
    m := make(map[string]int)

    // Add
    m["Alice"] = 30
    m["Bob"] = 25

    // Update
    m["Alice"] = 31

    fmt.Println(m)
}

Deleting

package main

import "fmt"

func main() {
    m := map[string]int{
        "Alice": 30,
        "Bob":   25,
        "Charlie": 35,
    }

    // Delete
    delete(m, "Bob")
    fmt.Println(m)  // map[Alice:30 Charlie:35]

    // Delete non-existent key (safe)
    delete(m, "David")
    fmt.Println(m)
}

Map Length

package main

import "fmt"

func main() {
    m := map[string]int{
        "Alice": 30,
        "Bob":   25,
    }

    fmt.Println(len(m))  // 2

    delete(m, "Alice")
    fmt.Println(len(m))  // 1
}

Map Iteration

Range Over Maps

package main

import "fmt"

func main() {
    person := map[string]string{
        "name": "Alice",
        "age":  "30",
        "city": "New York",
    }

    // Iterate with key and value
    for key, value := range person {
        fmt.Printf("%s: %s\n", key, value)
    }

    // Iterate with key only
    for key := range person {
        fmt.Println(key)
    }

    // Iterate with value only
    for _, value := range person {
        fmt.Println(value)
    }
}

Iteration Order

package main

import "fmt"

func main() {
    m := map[string]int{
        "a": 1,
        "b": 2,
        "c": 3,
    }

    // Maps don't guarantee order
    for key := range m {
        fmt.Println(key)
    }
    // Output order is random each time
}

Map Patterns

Counting Occurrences

package main

import "fmt"

func countWords(words []string) map[string]int {
    counts := make(map[string]int)
    for _, word := range words {
        counts[word]++
    }
    return counts
}

func main() {
    words := []string{"apple", "banana", "apple", "cherry", "banana", "apple"}
    counts := countWords(words)
    fmt.Println(counts)
    // Output: map[apple:3 banana:2 cherry:1]
}

Grouping Data

package main

import "fmt"

type Person struct {
    Name string
    City string
}

func groupByCity(people []Person) map[string][]Person {
    groups := make(map[string][]Person)
    for _, p := range people {
        groups[p.City] = append(groups[p.City], p)
    }
    return groups
}

func main() {
    people := []Person{
        {"Alice", "New York"},
        {"Bob", "Los Angeles"},
        {"Charlie", "New York"},
    }

    grouped := groupByCity(people)
    for city, residents := range grouped {
        fmt.Printf("%s: %v\n", city, residents)
    }
}

Caching Results

package main

import "fmt"

func fibonacci(n int, cache map[int]int) int {
    if n <= 1 {
        return n
    }

    if val, ok := cache[n]; ok {
        return val
    }

    result := fibonacci(n-1, cache) + fibonacci(n-2, cache)
    cache[n] = result
    return result
}

func main() {
    cache := make(map[int]int)
    fmt.Println(fibonacci(10, cache))
}

Map of Maps

Nested Maps

package main

import "fmt"

func main() {
    // Map of maps
    data := map[string]map[string]int{
        "Alice": {
            "math":    95,
            "english": 87,
        },
        "Bob": {
            "math":    88,
            "english": 92,
        },
    }

    // Access nested value
    fmt.Println(data["Alice"]["math"])  // 95

    // Add nested value
    data["Charlie"] = make(map[string]int)
    data["Charlie"]["math"] = 91

    fmt.Println(data)
}

Best Practices

โœ… Good: Check Key Existence

// DO: Check if key exists before accessing
if value, ok := m[key]; ok {
    fmt.Println(value)
} else {
    fmt.Println("Key not found")
}

โŒ Bad: Assume Key Exists

// DON'T: Assume key exists
value := m[key]  // Returns zero value if not found

โœ… Good: Use Appropriate Key Types

// DO: Use appropriate types for keys
m := make(map[string]int)      // String keys
m2 := make(map[int]string)     // Int keys
m3 := make(map[struct{}]bool)  // Struct keys

โœ… Good: Initialize Before Use

// DO: Initialize map before adding values
m := make(map[string][]int)
m["key"] = append(m["key"], 1)  // Safe

โŒ Bad: Nil Map

// DON'T: Use nil map
var m map[string]int
m["key"] = 1  // Panic!

Summary

Go maps provide:

  1. Efficient key-value storage with hash tables
  2. Fast lookups in O(1) average time
  3. Flexible key types (any comparable type)
  4. Safe access with comma-ok idiom
  5. Easy iteration with range

These features make maps essential for Go programming.

Comments