Как итерироваться по элементам map в отсортированном порядке (по ключам или значениям)?

Ответ

Важно понимать, что map в Go является неупорядоченной коллекцией. Порядок итерации по ее элементам не гарантируется и может меняться при каждом запуске программы. Чтобы получить элементы в отсортированном виде, необходимо выполнить несколько шагов.

1. Сортировка по ключам

Это самый распространенный сценарий. Алгоритм следующий:

  1. Создать срез для хранения ключей из map.
  2. Скопировать все ключи в этот срез.
  3. Отсортировать срез ключей с помощью пакета sort.
  4. Итерироваться по отсортированному срезу ключей, получая значения из map.
package main

import (
    "fmt"
    "sort"
)

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

    keys := make([]string, 0, len(m))
    for k := range m {
        keys = append(keys, k)
    }
    sort.Strings(keys) // Сортируем ключи

    for _, k := range keys {
        fmt.Printf("Ключ: %s, Значение: %dn", k, m[k])
    }
    // Вывод:
    // Ключ: a, Значение: 1
    // Ключ: b, Значение: 2
    // Ключ: c, Значение: 3
}

2. Сортировка по значениям

Этот подход немного сложнее. Нужно создать структуру для хранения пар ключ-значение, скопировать в нее данные из map и отсортировать срез этих структур.

package main

import (
    "fmt"
    "sort"
)

func main() {
    m := map[string]int{"Go": 95, "Rust": 98, "Python": 85}

    type kv struct {
        Key   string
        Value int
    }

    var ss []kv
    for k, v := range m {
        ss = append(ss, kv{k, v})
    }

    sort.Slice(ss, func(i, j int) bool {
        return ss[i].Value < ss[j].Value // Сортируем по значению
    })

    for _, pair := range ss {
        fmt.Printf("Ключ: %s, Значение: %dn", pair.Key, pair.Value)
    }
    // Вывод:
    // Ключ: Python, Значение: 85
    // Ключ: Go, Значение: 95
    // Ключ: Rust, Значение: 98
}