맵 선언 및 초기화
Go에서는 키-값 쌍을 저장하는 컬렉션으로 map을 제공한다. 맵은 순서가 보장되지 않으며, 요소가 추가된 순서와 무관하게 저장된다.
맵의 기본 형식은 다음과 같다:
map[KeyType]ValueType
여기서 KeyType은 키의 타입, ValueType은 해당 키에 매핑되는 값의 타입이다. 맵 변수는 기본적으로 nil 값을 가지므로, 메모리를 할당하기 위해 make() 함수를 사용해야 한다.
make(map[KeyType]ValueType, [cap])
cap 매개변수는 맵의 예상 용량을 지정하며, 선택적이나 권장되는 설정이다.
예시: 맵 생성 및 사용
func main() {
grades := make(map[string]int, 5)
grades["Alice"] = 85
grades["Bob"] = 92
fmt.Println(grades)
fmt.Println(grades["Bob"])
fmt.Printf("타입 확인: %T\n", grades)
}
결과:
map[Alice:85 Bob:92]
92
타입 확인: map[string]int
또한 초기화 시 바로 값들을 포함할 수 있다:
userInfo := map[string]string{
"id": "user001",
"role": "admin",
}
fmt.Println(userInfo)
키 존재 여부 확인
맵에서 특정 키가 존재하는지 확인하려면 다음과 같은 구문을 사용한다:
value, exists := myMap[key]
이 경우, exists는 true 또는 false를 반환하며, 값이 없으면 value는 해당 타입의 제로 값이다.
func main() {
scores := make(map[string]int)
scores["Charlie"] = 78
if val, found := scores["David"]; found {
fmt.Println("점수:", val)
} else {
fmt.Println("등록되지 않은 사용자입니다.")
}
}
맵 반복 처리 (for range)
for range 문을 사용해 맵의 모든 키-값 쌍을 순회할 수 있다.
func main() {
scores := map[string]int{
"Anna": 95,
"Tom": 88,
"Lily": 91,
}
for name, score := range scores {
fmt.Printf("%s: %d점\n", name, score)
}
}
키만 필요할 경우 아래처럼 작성 가능:
for key := range scores {
fmt.Println("이름:", key)
}
> ⚠️ 주의: 맵의 반복 순서는 삽입 순서와 무관하다.
요소 삭제
delete() 내장 함수를 통해 맵에서 특정 키-값 쌍을 제거할 수 있다.
delete(targetMap, key)
func main() {
scores := map[string]int{"Mike": 80, "Jane": 90, "Kate": 85}
delete(scores, "Jane")
for name, score := range scores {
fmt.Printf("%s: %d\n", name, score)
}
}
키 기준으로 정렬
맵 자체는 정렬되지 않으므로, 키를 별도로 추출하여 정렬해야 한다.
keys := make([]string, 0, len(testMap))
for k := range testMap {
keys = append(keys, k)
}
sort.Strings(keys)
fmt.Println("정렬된 키 순서:")
for _, k := range keys {
fmt.Printf("%s: %v\n", k, testMap[k])
}
값 기준으로 정렬
값을 기준으로 정렬하려면, 값들을 모아 정렬하고 역매핑을 통해 원래 키를 찾는 방식이 필요하다.
values := make([]int, 0, len(testMap))
for _, v := range testMap {
values = append(values, v)
}
sort.Ints(values)
// 역맵 생성 (값 -> 키)
reverseMap := make(map[int]string)
for k, v := range testMap {
reverseMap[v] = k
}
fmt.Println("값 기준 정렬:")
for _, v := range values {
fmt.Printf("%s: %d\n", reverseMap[v], v)
}
맵을 요소로 하는 슬라이스
슬라이스의 각 요소가 맵인 경우, 초기화에 주의해야 한다.
func main() {
var userProfiles = make([]map[string]string, 3)
for i, m := range userProfiles {
fmt.Printf("인덱스 %d: %v\n", i, m)
}
fmt.Println("초기화 후")
userProfiles[0] = make(map[string]string)
userProfiles[0]["name"] = "Alex"
userProfiles[0]["city"] = "Seoul"
userProfiles[0]["job"] = "Engineer"
for i, m := range userProfiles {
fmt.Printf("인덱스 %d: %v\n", i, m)
}
}
값이 슬라이스인 맵
각 키에 여러 값을 담고 싶다면, 값 타입으로 슬라이스를 사용하면 된다.
func main() {
countryCities := make(map[string][]string, 2)
cities := []string{"Tokyo", "Osaka"}
countryCities["일본"] = cities
// 새로운 도시 추가
countryCities["한국"] = append(countryCities["한국"], "서울", "부산")
fmt.Println(countryCities)
}
실습: 문자열에서 단어 빈도 분석
주어진 문장에서 각 단어의 등장 횟수를 세는 프로그램을 작성해보자.
package main
import (
"fmt"
"strings"
)
func main() {
text := "how do you do"
words := strings.Fields(text) // 공백 기준 분할
wordCount := make(map[string]int)
for _, word := range words {
wordCount[word]++
}
for word, count := range wordCount {
fmt.Printf("%s: %d\n", word, count)
}
}
출력 결과:
how: 1
do: 2
you: 1