Golang: Обход карт
Чтобы пройтись по всем элементам карты, в Go используется цикл for range
.
Полный перебор ключей и значений
Обычно при работе с картой нужны и ключ, и значение. Для этого используются две переменные:
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"Tom": 19,
}
for name, age := range ages {
fmt.Printf("%s is %d years old\n", name, age)
}
Пример вывода (порядок может быть любым):
Alice is 25 years old
Tom is 19 years old
Bob is 30 years old
В отличие от срезов, порядок обхода элементов карты не гарантируется — он может быть разным при каждом запуске программы. Это связано с внутренней реализацией map
и важно учитывать, если требуется получить данные в определённом порядке. Для этого ключи карты можно извлечь в срез, отсортировать и обойти уже его.
Перебор только ключей
Если нужно обойти только ключи, можно использовать одну переменную:
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"Tom": 19,
}
for name := range ages {
fmt.Println(name)
}
// => Alice
// => Bob
// => Tom
Перебор только значений
Если нужен только список значений, ключ можно пропустить, заменив его на _
:
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"Tom": 19,
}
for _, age := range ages {
fmt.Println(age)
}
// => 25
// => 30
// => 19
Проверка содержимого при переборе
Иногда нужно не просто вывести все элементы, а проверить условие для каждого из них. Например, найти первого человека старше 20 лет:
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"Tom": 19,
}
for name, age := range ages {
if age > 20 {
fmt.Printf("%s is older than 20\n", name)
break
}
}
// => Alice is older than 20
Пример с сортировкой ключей
Чтобы получить элементы карты в определённом порядке, нужно отдельно собрать ключи, отсортировать их и пройтись по ним:
import "slices"
ages := map[string]int{
"Alice": 25,
"Bob": 30,
"Tom": 19,
}
keys := []string{}
for name := range ages {
keys = append(keys, name)
}
slices.Sort(keys)
for _, name := range keys {
fmt.Printf("%s is %d years old\n", name, ages[name])
}
// => Alice is 25 years old
// => Bob is 30 years old
// => Tom is 19 years old
Преобразование карты в срез пар
Иногда бывает полезно сконвертировать карту в срез структур для дальнейшей обработки (например, сортировки по значениям):
import "slices"
type Person struct {
Name string
Age int
}
var people []Person
for name, age := range ages {
people = append(people, Person{Name: name, Age: age})
}
// Теперь people можно отсортировать по возрасту:
slices.SortFunc(people, func(a, b Person) int {
return a.Age - b.Age
})
Задание
Реализуйте функцию CountWords(text string) map[string]int
, которая принимает строку text
и возвращает карту, где каждому слову соответствует количество его вхождений.
Слова выделяются на основе пробелов, при этом регистр букв игнорируется — все слова должны учитываться в нижнем регистре. Кроме того, из слов удаляются знаки пунктуации в начале и конце (например, !
, ?
, .
, ,
, ;
, :
).
Примеры:
CountWords("Go Go go!")
// map[go:3]
CountWords("Hello world hello")
// map[hello:2 world:1]
CountWords("Hi, hi! Hi.")
// map[hi:3]
Подсказки:
- Используйте
strings.ToLower()
для приведения текста к нижнему регистру. - Для разбиения текста на слова удобно применять
strings.FieldsSeq()
. - Для удаления пунктуации используйте
strings.Trim()
.
Команда проекта находится в телеграм-сообществе. Там можно задать любой вопрос и повлиять на проект
Если вы зашли в тупик, то самое время поговорить с нашим асситентом Тота во вкладке "ИИ-помощник":
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи. В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в обратной связи нашего сообщества
Ваше упражнение проверяется по этим тестам
package solution
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCountWords(t *testing.T) {
tests := []struct {
name string
input string
expected map[string]int
}{
{
name: "Simple case",
input: "Go Go go!",
expected: map[string]int{"go": 3},
},
{
name: "Mixed words",
input: "Hello world hello",
expected: map[string]int{"hello": 2, "world": 1},
},
{
name: "Empty string",
input: "",
expected: map[string]int{},
},
{
name: "With punctuation",
input: "Hi, hi. Hi?",
expected: map[string]int{"hi": 3},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := CountWords(tt.input)
assert.Equal(t, tt.expected, result)
})
}
}
Решение учителя откроется через:
20:00
