웹개발일지

Go 자료구조 : map [맵] 본문

Lang/Go

Go 자료구조 : map [맵]

hee_log 2022. 12. 24. 23:51
728x90

이 글은 아래 링크 자료를 참고 및 번역하여 Go의 맵 자료형에 대해 조사한 내용입니다. 

 

https://articles.wesionary.team/map-types-in-golang-24591abbafc6

 

map Types in Golang

What is actually a map in Golang?.

articles.wesionary.team



 

 

맵 자료형 

 

 

 Go의 맵은 특정 데이터 타입을 지칭한다기 보다, 다른 데이터 타입들을 'key'와 'value'로서 사용하기위해 만들어 쓴다. 

 

기본형태 

TYPE{
	KEY: VALUE,
    ...
}

 맵의 기본 형태이다.

 

 

map[string]int

 

 map[string]int는 string을 key로 사용하고 int를 value로 사용하겠다는 정의이다. 

 

 

key 와 value 타입에 어떤것을 사용하느냐 

 

 맵을 정의할 때 슬라이스와 함수를 사용할 수 있을까? 정답은 아니오다. 왜냐, 키는 무조건 비교 연산이 가능한 타입이어야 하는 것인데, Go의 기본 자료형인 string, int와 같은 것을 제외하고는 비교 연산이 불가하다. 그렇기 때문이 func와 slice는 맵의 키로 사용할수가 없다. 같은 이유로 맵의 키로서 맵을 사용할 수 없다. 

 

 하지만 맵의 value에는 제한이 없다. 그 어떠한 타입도 올 수 있다. 만약, 값으로 아무것도 넣지 않는다면 비어있는 맵 자료형으로 초기화 하게 되는 것이다. 표현식은 아래와 같다. 

var menuprice map[string]int{}

  이를 사용은 가능하다. 하지만 nil값을 읽거나 쓸수는 없다. 


 

그렇다면 맵을 어떻게 저장하고 사용할까? 

 

 1. 맵에 특정 키값이 존재하는지 확인하자 

menuprice, ok := menu["cheeseburger"]
if ok {
	return fmt.Sprintf("Yes, cheeseburger is on the menu;%f", menuprice)

}
return fmt.Sprint("no any cheeseburger!")

  여기서 키 값이 매칭된다면 ok값으로 true가 반환될 것이다. 그렇지 않으면 false가 반환될 것이다. 반환 값의 첫번째 인자로 받을 것 이 없다면 menuprice를 선언하는 것 대신 _ (언더바 기호)를 붙여 '_, ok :='로 생략하여 선언할 수 있다. 

 

2. 불리언 형태의 맵을 값으로 

우리가 현재 가진 재료들의 재고를 표현한 inStock 이라는 맵을 예시로 보자. 

var inStock = map[string]bool {
	"eggs":    true,
    "buffsausage":   true,
    "chickensausage": true,
}

 특정 item을 인자로 받아 그것이 inStock에 있는지 어떻게 확인할 수 있을까? value('_'로 표현)와 ok 를 결괏값으로 확인하면 된다. 주어진 인자를 key값으로 맵에 조회하여 해당 key가 존재하는지 검사하면 value와 그 결과를 ok를 통해 알 수 있다.  만약 false를 결과로 갖는다면 출력값으로 메시지와 함께 인자로 넣었던 key name을 다시 반환하자. 

if _, ok := inStock[eggs]; ok {
    return fmt.Sprintf("is in stock", eggs)
}
return fmt.Sprintf("Sorry, out of stock", eggs)

 

 

3. 맵을 순회 하는 방법 

 range 연산자를 사용하여 맵을 순회하고 값을 받아보자. key-value 각각을 읽어 변수값으로 할당받게 된다. 

for x, y:= range instock{
fmt.Println(x,y)
}

 루프를 돌 때 마다 다음 key값으로 넘어가면서 그 key값에 일치하는 value값을 찾는다. 

 

4. map에 자료 append()하기 

var dishes []string
for dish:= range instock{
  dishes = append(dishes, dish)
}
fmt.Println(dishes)
sorteddishes:= sort.Strings(dishes)
fmt.Println(sortdishes)

1. string형태 자료들이 담긴 슬라이스 변수 dishes를 선언했다. 

2. 맵 자료형 변수 instock을 순회한 값을 dish에 담았다. dish 값은 dishes에 append 로 추가되었다. 빈 문자열 슬라이스에 instock 의 자료들이 하나씩 들어가게된다. 

 

위 출력 결과가 매번 순서가 다르게 나와서 찾아보니 맵은 순서보장이 안된다고 한다. 순서가 보장되는 것을 원한다면 key를 지정해서 사용해야 한다. 

 

5. Go가 자료를 순회하는 방법 

더보기

Iteration order

When iterating over a map with a range loop, the iteration order is not specified and is not guaranteed to be the same from one iteration to the next. If you require a stable iteration order you must maintain a separate data structure that specifies that order. This example uses a separate sorted slice of keys to print a map[int]string in key order:

import "sort"

var m map[int]string
var keys []int
for k := range m {
    keys = append(keys, k)
}
sort.Ints(keys)
for _, k := range keys {
    fmt.Println("Key:", k, "Value:", m[k])
}

 

 맵에는 해시 맵과 sorted맵이 있는데 첫번째는 정렬되지 않고 순서가 보장되지 않으며 이것이 Go의 맵이라고 한다. sorted 맵은 키값으로 정렬이 된다. 그러니까 Go의 맵은 내부에서 요소를 보관할 때 입력한 순서와도 키 값과도 상관없이 데이터를 보관하는 원리라고 한다. 맵의 동작을 자세히 이해하려면 해시 함수의 동작을 이해해야한다고 한다. 

 

6. map[string]interface{}

 

 interface{} 가 무엇일까? 어떠한 메소드도 갖지 않는다. 하지만 그것이 빈 인터페이스가 어떤 메서드도 가져선 안된다는 걸 말하는 게 아니다! 빈 인터페이스는 어떠한 값도 받을 수 있다. string, int, struct, pointer와 같은 자료들 말이다. 

 

  - examples below

menus := map[string]interface{}{
  "icecream": "delicious",
  "eggs": struct {
    price  float64
  }{"chicken", 1.75},
  "chickenSteak": true,
}
type Person struct {
    Name    string
    Age     int
    Hobbies []string
}

person:=map[string]interface{
   "name":"John",
   "age":29,
   "hobbies":[
      "martial arts",
      "breakfast foods",
      "piano"
   ]
}

 

7. 언제 map[string]interface{} 를 사용할까? 

 

 위 타입은 우리가 데이터를 다룰 때 매우 유용하게 쓰인다. 마치 여러 자료형태가 뒤섞인 JSON 자료형같은 걸 다룰 때 말이다. 

 

 

 


 

 이렇게 Go언어의 맵 자료형에 대해 조사하고 기초 예제를 복습해보았다. 처음 입문서로 배울 땐 막연하게 key와 value 데이터로 이루어진 자료구조라는 것 정도로만 이해하고 있었는데 유용하게 쓰이는 것 같다. 알고리즘 문제풀이를 하면서 맵의 동작원리에 대해 더 공부해보도록 해야겠다.