Golang: Практики использования карт
Полезные приёмы работы с картами
Рассмотрим наиболее полезные приёмы (паттерны) при работе с картами. В некоторых случаях мы будем использовать библиотеку samber/lo, которая предоставляет готовые функции для работы с коллекциями и картами.
Инкремент значений (счётчики)
Карты отлично подходят для подсчёта чего-либо. Если ключ отсутствует, доступ map[key]
возвращает нулевое значение:
words := map[string]int{}
words["go"]++
words["go"]++
fmt.Println(words["go"]) // => 2
Установка значения по умолчанию
С помощью lo.GetOrElse()
можно задать значение по умолчанию, если ключ отсутствует:
import "github.com/samber/lo"
defaults := map[string]string{
"theme": "light",
}
lang := lo.GetOrElse(defaults, "lang", "en")
fmt.Println(lang) // => en
Сбор ключей или значений
Чтобы получить список всех ключей карты, используйте maps.Keys()
:
import "maps"
keys := maps.Keys(users)
fmt.Println(keys) // => [alice bob]
Чтобы собрать значения:
import (
"fmt"
"maps"
)
values := maps.Values(users)
fmt.Println(values) // => [25 30]
Если нужно отсортировать ключи:
import (
"fmt"
"slices"
"maps"
)
keys := maps.Keys(users)
slices.Sort(keys)
fmt.Println(keys) // => [alice bob]
Вложенные карты (инициализация на лету)
Когда значение карты само является картой, полезен следующий паттерн:
settings := map[string]map[string]string{}
user := "alice"
if settings[user] == nil {
settings[user] = make(map[string]string)
}
settings[user]["theme"] = "dark"
При первом обращении к settings["alice"]
, если такого ключа ещё нет, Go вернёт nil
, но не ошибку.
Однако если мы попытаемся сразу обратиться к settings["alice"]["theme"]
, не проверяя, инициализирована ли внутренняя карта, будет паника времени выполнения.
Этот шаблон — инициализация на лету: если для ключа ещё нет вложенной карты, она создаётся сразу перед использованием.
Задание
Реализуйте функцию CountLanguages(users map[string]string) map[string]int
, которая принимает карту users
, где ключ — имя пользователя, а значение — язык программирования, и возвращает карту с подсчётом количества пользователей для каждого языка.
Пример:
users := map[string]string{
"Alice": "Go",
"Bob": "Python",
"Tom": "Go",
"Kate": "Java",
}
result := CountLanguages(users)
fmt.Println(result)
// map[Go:2 Java:1 Python:1]
Полезное
samber/lo - библиотека с полезными функциями для слайсов, карт и не только для них
maps - встроенные функции для работы с мапами.
Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект
Если вы зашли в тупик, то самое время поговорить с нашим асситентом Тота во вкладке "ИИ-помощник":
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи. В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в обратной связи нашего сообщества
Ваше упражнение проверяется по этим тестам
package solution
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCountLanguages(t *testing.T) {
users := map[string]string{
"Alice": "Go",
"Bob": "Python",
"Tom": "Go",
"Kate": "Java",
}
expected := map[string]int{
"Go": 2,
"Python": 1,
"Java": 1,
}
assert.Equal(t, expected, CountLanguages(users))
}
func TestEmptyUsers(t *testing.T) {
users := map[string]string{}
expected := map[string]int{}
assert.Equal(t, expected, CountLanguages(users))
}
Решение учителя откроется через:
20:00
