Question

How to Get a Slice of Map Keys in Go

godictionaryslice

Question

In Go, is there a simpler or more idiomatic way to get a slice of keys from a map?

Right now, I am iterating over the map and copying each key into a slice:

i := 0
keys := make([]int, len(mymap))
for k := range mymap {
    keys[i] = k
    i++
}

I want to know whether Go provides a cleaner built-in approach, or whether manually iterating over the map is the standard way to do this.

Short Answer

By the end of this page, you will understand how to extract keys from a map in Go, why iteration is the normal approach, and how to write this pattern clearly and safely. You will also learn when to preallocate a slice, when to use append, and how to sort keys when order matters.

Concept

In Go, a map is an unordered collection of key-value pairs. If you want all keys from a map, you must iterate over the map and collect them yourself.

There is no built-in function in the standard language syntax that directly returns a slice of keys for any map. The idiomatic approach is to use a for range loop.

Why this matters:

  • Maps are used everywhere in Go for lookups, caching, grouping, and counting.
  • Very often, you need the keys separately for display, sorting, or further processing.
  • Understanding that map iteration is explicit helps you write predictable and readable Go code.

A key detail is that map iteration order is not guaranteed. That means the slice of keys you build may come out in a different order each time. If you need a stable order, you must sort the keys after collecting them.

There are two common ways to build the keys slice:

  • Preallocate with make and fill by index
  • Start empty and use append

Both are valid. In many cases, using append is a little cleaner and easier to read.

Mental Model

Think of a Go map like a box of labeled index cards.

  • The label on each card is the key.
  • The content written on the card is the value.
  • If you want a list of all labels, you must pick up each card one by one and copy its label into a new list.

Go does not hand you a ready-made list of labels automatically. You create that list by walking through the box yourself.

Take Quiz

Syntax and Examples

Basic pattern

The standard way to get keys from a map is:

keys := make([]int, 0, len(m))
for k := range m {
    keys = append(keys, k)
}

Why this version is nice

  • make([]int, 0, len(m)) creates an empty slice
  • It reserves enough capacity for all keys
  • append keeps the code simple

Example

package main

import "fmt"

func main() {
    mymap := map[int]string{
        10: "apple",
        20: "banana",
        30: "orange",
    }

    keys := make([]int, 0, len(mymap))
    for k := range mymap {
        keys = append(keys, k)
    }

    fmt.Println(keys)
}

Possible output:

[20 30 10]

The order may change between runs.

Alternative: fill by index

Your original approach is also valid:

i := 0
keys := make([]int, len(mymap))
for k := range mymap {
    keys[i] = k
    i++
}

This works because the slice already has the exact final length.

If you need sorted keys

package main

import (
    "fmt"
    "sort"
)

func main() {
    mymap := map[int]string{
        10: "apple",
        20: "banana",
        30: "orange",
    }

    keys := make([]int, 0, len(mymap))
    for k := range mymap {
        keys = append(keys, k)
    }

    sort.Ints(keys)
    fmt.Println(keys)
}

Output:

[10 20 30]

This is the correct approach when order matters.

Step by Step Execution

Consider this code:

m := map[int]string{
    5: "a",
    2: "b",
    9: "c",
}

keys := make([]int, 0, len(m))
for k := range m {
    keys = append(keys, k)
}

Step by step:

  1. m is created with 3 key-value pairs.
  2. len(m) is 3.
  3. make([]int, 0, len(m)) creates:
    • a slice of length 0
    • a capacity of 3
  4. The loop for k := range m starts iterating over the map.
  5. On each iteration, Go gives one key from the map.
  6. append(keys, k) adds that key to the slice.
  7. After all iterations, keys contains all map keys.

A possible trace:

  • First iteration: k = 9 → keys = [9]
  • Second iteration: k = 5 → keys = [9 5]
  • Third iteration: k = 2 → keys = [9 5 2]

Another run could produce a different order.

If you sort afterward:

sort.Ints(keys)

Then the final result becomes:

[2 5 9]

Real World Use Cases

Getting keys from a map is common in real Go programs.

1. Displaying available IDs

You may store records in a map and need to list all IDs:

users := map[int]string{
    101: "Ava",
    102: "Noah",
}

You can extract the keys to show which users exist.

2. Sorting configuration names

A service might load feature flags into a map:

flags := map[string]bool{
    "betaUI": true,
    "logging": false,
}

You collect the keys, sort them, and print them in a stable order.

3. Building API responses

Sometimes your internal data is stored as a map, but the API response needs a list of keys or IDs.

4. Validating allowed values

You might keep allowed values in a map for fast lookup, then later need the keys for an error message:

allowed := map[string]struct{}{
    "json": {},
    "xml":  {},
}

If the user passes an invalid format, you can return the list of valid formats.

5. Data processing and reporting

When counting grouped values, the final report may require the group names as a slice:

counts := map[string]int{
    "books":  12,
    "games":  7,
    "movies": 4,
}
Take Quiz

Real Codebase Usage

In real Go codebases, developers usually use one of these patterns.

Pattern 1: Extract keys with append

This is the most readable general-purpose style:

keys := make([]string, 0, len(settings))
for k := range settings {
    keys = append(keys, k)
}

Pattern 2: Sort immediately when order matters

This is very common in CLI tools, logs, tests, and API output:

keys := make([]string, 0, len(settings))
for k := range settings {
    keys = append(keys, k)
}
sort.Strings(keys)

Pattern 3: Helper function

Teams often wrap this in a small helper for repeated use:

func mapKeys(m map[string]int) []string {
    keys := make([]string, 0, len(m))
    for k := range m {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    return keys
}

Pattern 4: Use for validation messages

Maps are often used as sets in Go. Then keys are extracted for user-facing output:

validRoles := map[string]struct{}{
    "admin":  {},
    "editor": {},
    "viewer": {},
}

When validation fails, developers gather and sort the keys to produce a clear message.

Pattern 5: Stable output in tests

Because map order is not stable, tests often fail if they compare unsorted map-derived slices. A common fix is:

keys := make([]string, 0, len(m))
for k := range m {
    keys = append(keys, k)
}
sort.Strings(keys)

This avoids flaky tests.

Common Mistakes

1. Expecting map keys to come out in a fixed order

Broken assumption:

m := map[int]string{1: "a", 2: "b", 3: "c"}
keys := make([]int, 0, len(m))
for k := range m {
    keys = append(keys, k)
}

// Do not assume keys == [1, 2, 3]

Fix

Sort the slice if order matters.

sort.Ints(keys)

2. Mixing up slice length and capacity

Broken code:

keys := make([]int, 0, len(m))
for k := range m {
    keys[i] = k // panic: index out of range
    i++
}

Why it breaks:

  • Length is 0, so keys[0] is invalid
  • Capacity is reserved, but elements do not exist yet

Fix

Use append:

keys := make([]int, 0, len(m))
for k := range m {
    keys = append(keys, k)
}

Or create the slice with full length if you want index assignment:

keys := make([]int, len(m))
i := 0
for k := range m {
    keys[i] = k
    i++
}

3. Forgetting to increment the index

Broken code:

i := 0
keys := make([]int, len(m))
for k := range m {
    keys[i] = k
}

This keeps writing to the same position and will not work correctly.

Fix

Increment i each time, or switch to append.

4. Assuming Go has a universal built-in keys() for maps

Go's core map handling is explicit. You typically write the loop yourself or create a helper function.

5. Using unsorted keys in tests

Broken test idea:

want := []string{"a", "b", "c"}

If got comes from a map without sorting, the order can differ.

Fix

Sort both sides or sort the extracted keys before comparison.

Comparisons

Common ways to collect map keys

ApproachExampleProsConsWhen to use
Preallocate full length and assign by indexkeys := make([]int, len(m))Efficient, no append callsNeeds manual index variableWhen you know exact length and are comfortable managing i
Empty slice with capacity and appendkeys := make([]int, 0, len(m))Readable, idiomatic, less error-proneSlightly more abstract for beginnersBest default choice
Empty slice without capacityvar keys []int then appendShort and simpleMay reallocate as it growsFine for small maps or quick code
Helper functionfunc keys(m map[string]int) []stringReusable, clean call sitesExtra function to maintainUseful when repeated often

append vs index assignment

StyleExampleMain idea
appendkeys = append(keys, k)Grow the slice one element at a time
Index assignmentkeys[i] = kFill an already-sized slice at known positions

Ordered vs unordered results

SourceOrder guaranteed?
Iterating a Go mapNo
Sorting keys after extractionYes

If your program depends on order, extract first, then sort.

Take Quiz

Cheat Sheet

Key pattern

keys := make([]K, 0, len(m))
for k := range m {
    keys = append(keys, k)
}

Replace K with the map key type.

Example with int keys

keys := make([]int, 0, len(m))
for k := range m {
    keys = append(keys, k)
}

Example with string keys

keys := make([]string, 0, len(m))
for k := range m {
    keys = append(keys, k)
}

If order matters

sort.Ints(keys)
sort.Strings(keys)

Alternative indexed version

i := 0
keys := make([]int, len(m))
for k := range m {
    keys[i] = k
    i++
}

Rules to remember

  • Go maps are unordered
  • There is no built-in map-to-keys conversion in basic syntax
  • Iteration is the normal way to collect keys
  • Use append for cleaner code in many cases
  • Sort keys if you need predictable output

Common trap

This is wrong:

keys := make([]int, 0, len(m))
keys[0] = 10

Why: length is 0, so index 0 does not exist yet.

FAQ

Is there a built-in Go function to get all map keys?

Not in the basic language syntax for ordinary maps. The standard approach is to iterate with for range and collect the keys.

What is the idiomatic way to get map keys in Go?

Usually:

keys := make([]KeyType, 0, len(m))
for k := range m {
    keys = append(keys, k)
}

Why is my keys slice in a different order each run?

Because Go map iteration order is not guaranteed. Sort the keys if you need stable output.

Should I use append or assign by index?

Both work. append is often easier to read and less error-prone. Index assignment is fine if you pre-size the slice correctly.

Why use make([]T, 0, len(m)) instead of just var keys []T?

It preallocates enough capacity for all keys, which can reduce reallocations while keeping the code simple.

Can I get both keys and values during iteration?

Yes:

for k, v := range m {
    fmt.Println(k, v)
}

Do I need to sort keys in tests?

Usually yes, if your expected result depends on order. Otherwise tests may be inconsistent.

Take Quiz

Mini Project

Description

Build a small Go program that stores a set of product IDs in a map and then extracts the keys into a slice. This demonstrates the standard pattern for collecting map keys, and it also shows how to sort them for stable output.

Goal

Create a program that reads keys from a map, stores them in a slice, sorts the slice, and prints the result.

Requirements

  • Create a map with at least five integer keys
  • Extract all keys into a slice using a for range loop
  • Use append to build the slice
  • Sort the keys before printing
  • Print the final sorted slice
Take Quiz

Keep learning

Related questions

View more