Карты в Golang

После изучения данного урока вы сможете:

  • Использовать карты в качестве наборов неструктурированных данных;
  • Объявлять, получать доступ и итерировать через карты;
  • Использовать преимущества ассоциативного массива.

Карты могут пригодиться во время поиска, и речь идет не только о картах Google Maps. Go предоставляет коллекцию карт с ключами, что указывают на значения. В то время, как массивы и срезы индексируются через последовательные целые числа, ключи карт могут быть представлены практически любым типом.

Форум Гоферов

Мы работаем над форумом для программистов на Golang. Очень нужны модераторы которые хотят помочь с ответами для новичков и помочь в развитии Go-сообщества.

Go на Форум

Уроки, статьи и Видео

Мы публикуем в паблике ВК и Telegram качественные обучающие материалы для быстрого изучения Go. Подпишитесь на нас в ВК и в Telegram. Поддержите сообщество Go программистов.

Go в ВК Go в Telegram

Содержание статьи

У коллекций подобного рода есть свои названия в разных языках: словари в Python, хеши в Ruby и объекты в JavaScript. Ассоциативные массивы в PHP и таблицы в Lua являются одновременно картами и обычными массивами.

Карты особенно полезны для неструктурированных данных, где ключи определяются во время работы программы. Программы, созданные через скриптовые языки, часто используют карты и для структурированных данных — тех данных, ключи которых известны заранее. В дальнейших уроках мы в подробностях рассмотрим структурированный тип, что лучше всего подходит для таких случаев.

Карты связывают ключ со значением, что удобно для индекса. Если вам известно название книги, итерация каждой книги в массиве займет много времени. Это похоже на просмотр каждой полки каждого стеллажа библиотеки или книжного магазина. Карта с ключом названия книги значительно ускоряет процесс.

Подумайте, в каких случаях карты с ключами к значениям могут быть полезны?

Объявление карты в Golang

Ключи карты могут быть практически любого типа, в отличие от массивов и срезов, где для ключей используется последовательность целых чисел. Тип для ключей и значений в Go нужно уточнять. Для объявления карты с ключами типа string и значениями типа int используется синтаксис map[string]int. Схема дается ниже.

карта golang

Карта с ключами типа string и значениями типа integer

Карта temperature, объявленная в Листинге 1, содержит средние значения температуры Планетарного информационного бюллетеня. Как и другие коллекционные типы, карты можно объявлять и инициализировать через композитные литералы. Для поиска значений по ключу, присваивания поверх существующих значений или добавления значений в карту используются квадратные скобки [].

При попытке получить доступ к ключу, которого нет в карте, результатом будет нулевое значение типа (int):

В Go используется синтаксис comma, ok, что нужен для обозначения разницы между ключом "Луна", которого нет в карте, и тем, что находится в карте с температурой 0° C:

Переменная moon должна содержать значение ключа "Луна" или же нулевое значение. При наличии ключа значение дополнительной переменной ok будет равно true,  в противном случае — false.

При использовании синтаксиса comma, ok можно использовать любые названия переменных:

Вопросы для проверки:

  1. Какой тип вы используете для объявления карты с ключами, представленными 64-битными вещественными числами, и значениями, что являются целыми числами?
  2. При модификации Листинга 1 таким образом, что ключ "Луна" был бы представлен со значением 0, каким будет результат использования синтаксиса comma, ok?

Копируются ли карты в Golang?

Ранее мы упоминали, что массивы копируются во время присваивания к новым переменным или передачи к функциям или методам. То же самое верное в отношении примитивных типов вроде int или float64.

Карты устроены иначе. В следующем примере planets и planetsMarkII делят одну и ту же базовую информацию. Как видите, изменения в одном, затрагивают и другой. Это не всегда кстати.

Когда встроенная функция delete удаляет элемент из карты, как planets, так и planetsMarkII изменяются. При передачи карты функции или методу содержимое карты может измениться. Такое поведение напоминает несколько срезов, что указывают на один и тот же базовый массив.

Вопросы для проверки:

  1. Почему изменения в planets из Листинга 2 также отражаются на planetsMarkII?
  2. Что делает встроенная функция delete?

Предварительное обозначение карты через make

Некоторые аспекты карт напоминают срезы. Только если вы не инициализировали их через композитный литерал, карты нужно обозначить через встроенную функцию make.

Для карт make принимает один или два параметра. Второй предварительно обозначает место для количества ключей, что напоминает вместимость срезов. При использовании make начальная длина карты всегда будет нулевой:

Вопрос для проверки:

В чем преимущество предварительного обозначения карты через make?

Использование карты для подсчета частоты использования элементов

В Листинге 3 определяется частота упоминания температур, значения взяты из MAAS API. Если бы frequency была срезом, ключи были бы целыми числами, а базовому массиву потребовалось бы зарезервировать место для подсчета температур, что в действительности не был произведен. Для таких случаев карта намного удобнее.

Итерация через ключевое слово range работает одинаково со срезами, массивам и картами. Вместо индекса и значения, для итерации карты используется ключ и значение. Обратите внимание, что Go не гарантирует порядок ключей карты, поэтому выводы при различных запусках могут отличаться.

Вопрос для проверки: 

При итерации через карту чем заполняются две переменные?

Группирование данных с картами и срезами Golang

Вместо определения частоты упоминания температур сгруппируем их вместе с разделением каждой в 10°. Для этого в следующем пример карты группируются в срез температур данной группы.

Результат программы:

Вопрос для проверки:

Какого типа ключи и значения в объявлении var groups map[string][]int?

Множества в Golang

Множество является коллекцией, похожей на массив. Отличие в том, что каждый элемент должен повторяться только один раз. В Go коллекций множеств, но вы всегда можете сымпровизировать, используя карту, как показано в следующем примере. Значение не важно, но true удобно для проверки того, является ли элемент частью множества. Если температура находится в карте, ее значение true, это часть множества.

Видно, что карта содержит по одному ключу для каждой температуры, дубликаты удаляются. У ключей карты произвольный порядок, поэтому перед их сортировкой температуры нужно конвертировать обратно в срез:

Вопрос для проверки:

Как проверить, является ли 32.0 частью множества set?

Заключение

  • Карты являются универсальными коллекциями для неструктурированных данных;
  • Композитные литералы удобны для инициализации карт;
  • Ключевое слово range может итерировать через карты;
  • Карты делят одинаковые базовые данные, когда присваиваются или передаются функциям;
  • Коллекции становятся надежнее при объединении друг с другом.

Итоговое задание для проверки:

Напишите функцию для подсчета частоты упоминания слов в строке текста и возвращения карты со словами и числом, указывающем, сколько раз они употребляются. Функция должна конвертировать текст в нижний регистр и обрезать знаки препинания. Используйте пакет strings. Функции, которые пригодятся для выполнения данного задания: Fields, ToLower и Trim.

Используйте функцию для подсчета частоты слов следующего отрывка текста и последующего вывода числа употребления каждого слова, что встречается более одного раза.

As far as eye could reach he saw nothing but the stems of the great plants about him receding in the violet shade, and far overhead the multiple transparency of huge leaves filtering the sunshine to the solemn splendour of twilight in which he walked. Whenever he felt able he ran again; the ground continued soft and springy, covered with the same resilient weed which was the first thing his hands had touched in Malacandra. Once or twice a small red creature scuttled across his path, but otherwise there seemed to be no life stirring in the wood; nothing to fear—except the fact of wandering unprovisioned and alone in a forest of unknown vegetation thousands or millions of miles beyond the reach or knowledge of man.

C.S. Lewis, Out of the Silent Planet