본문 바로가기

Programming/Swift for Beginners

[Swift] 018 Dictionary (사전) for beginners



딕셔너리(The Dictionary)


사전을 생각하면 유명한 사전 편집자인 대니얼 웹스터(Daniel Webster)가 떠오를 것입니다. 도서관 서가에 꽂혀 있는 사전에는 뜻을 자세하게 설명한 단어들이 잘 정리되어 있습니다. 또한, 사전에서 단어의 정의를 찾을 때는 알파벳 순서대로 찾습니다. Swift 언어의 딕셔너리(Dictionary)도 우리가 알고 있는 사전처럼 사용합니다.

딕셔너리는 같은 타입을 가진 여러개의 값을 저장하는 하나의 컨테이너라고 볼 수 있습니다. 각각의 값은 유일한 키(key)와 값(value)에 물려 있으며, 이 키와 값은 딕셔너리 안에서 해당 값을 찾기 위한 식별자의 역할을 합니다. 배열의 값들과 달리 딕셔너리 안에 저장된 값은 어떤 순서가 정해져 있지 않습니다. 그래서, 실제로 사전에서 어떤 단어를 찾는 것과 같은 방식으로 딕셔너리 안에 정의된 식별자를 이용해서 값을 찾습니다.

딕셔너리에 대한 공부를 시작해보겠습니다. 식품 첨가물 중 하나인 고추를 예제로 사용하겠습니다. 어떤 고추는 다른 것보다 더 매울 수 있습니다. 그리고 이런 "매운" 정도를 측정할 때 스코빌 지수(Scoville units)를 사용합니다. 딕셔너리를 사용해 스코빌 지수의 부분 집합을 정의하겠습니다. 각각의 항목의 키는 고추 이름입니다. 값은 고추의 매운 정도에 대한 스코빌 지수를 넣습니다.

4개의 항목으로 딕셔너리를 만들었습니다. Poblano의 스코빌 지수는 1,000, Serrano는 700, Red Amazon은 75,000, Red Savina Habanero는 무려 500,000 입니다. 

* NOTE: Swift 딕셔너리의 순서는 사용하는 Xcode 버전에 따라 달라집니다. 그렇지만, Swift는 검색 및 액세스하는데 가장 효율적인 순서를 사용합니다.

딕셔너리를 선언할 때 Swift는 키(key)와 값(value)의 타입을 다시 한번 추론하게 됩니다. 키(key)는 확실히 문자열형이고 값(value)는 정수형입니다. 이 내용은 REPL 선언의 결과를 통해 확인할 수 있습니다. 숫자에 사용된 밑줄 표시는 천 단위로 구분하기 위해 사용되었습니다. 밑줄 표시는 문법적인 편의일 뿐이지 정수형의 값을 가지는 것은 아닙니다. 실행 후 나타나는 결과물에는 밑줄 표시 없이 숫자만 보여줍니다.

위 예제에서 이상한 점을 발견하셨습니까? REPL 결과를 자세히 살펴보면, 선언한 딕셔너리의 순서와 결과물로 보여진 딕셔너리의 순서가 다릅니다. 선언한 것과는 다른 순서로 표기가 되었습니다. 이렇게 순서가 다른 것이 Swift 딕셔너리의 중요한 부분입니다. Swift는 정의한 순서대로 출력하는 것이 아니라 가장 빠르게 액세스를 할 수 있는 적절한 메서드를 사용하라고 키(key)에게 명령합니다. 그러니 선언한 딕셔너리의 순서가 그대로 저장된다고 생각하면 안됩니다.

항목 찾기(Looking up an entry)

딕셔너리에 있는 항목에 액세스하는 것은 배열에 있는 값에 액세스하는 것과 유사합니다. 배열의 값은 괄호로 묶여 있다는 점이 유일하게 다른 점입니다. 배열에서는 0,1,2,3 처럼 값이 번호 순서대로 사용되었습니다. 딕셔너리에서는 항목의 값을 찾으려고 실제 키(key)를 사용합니다.

Int 선언문에 물음표가 있는 것이 보이시나요? 앞서 언급했듯이 물음표는 옵셔널한 값을 가지고 있으며, 값이 nil이 될 수 있다는 것을 의미합니다. 딕셔너리 값의 반환 값은 항상 옵셔널하지만 아래 예제에서 보여주듯이 nil을 값으로 사용해야 하는 것은 아닙니다.

그러나 위의 에러 내용을 보니 nil이 유효한 값이 아니라고 얘기하고 있습니다. 키(key)도 마찬가지입니다.

그럼 딕셔너리에 있는 값에 대해 요청하는데 왜 옵셔널 타입으로 값을 반환했을까요? 스코빌 지수 딕셔너리를 다시 보도록 하겠습니다.

딕셔너리에 동일한 4개의 항목이 아직도 있습니다. 존재하지 않는 값을 가진 키(key)를 요청하면 어떻게 될까요? Tabasco 고추에 대한 스코빌 지수가 있는지 확인해 보겠습니다.

반환 값이 nil입니다.

 이 점 때문에 딕셔너리의 값을 옵셔널 타입으로 반환하는 것입니다. 딕셔너리에 존재하지 않는 키(key)를 요청할 가능성이 있기 때문입니다. Swift의 장점이 다시 한번 빛을 발하는 순간입니다. Swift는 예외적이고 변칙적인 행동은 용납하지 않는 안전한 환경을 제공하는 장점이 있습니다.

항목 추가(Adding an entry)

이제 스코빌 지수 딕셔너리에 존재하지 않는 고추를 요청하면 어떤 결과가 나오는지 알게 되었습니다. 그럼 Tabasco 고추를 딕셔너리에 추가해 보겠습니다. 이미 딕셔너리를 선언할 때 var 키워드를 사용해서 가변하는 딕셔너리로 선언했기 때문에 아래 예제처럼 확장도 가능합니다.

그럼 제대로 추가되었는지 확인해 보겠습니다.

새로 추가된 "Tabasco"가 딕셔너리에 추가되었지만, 순서는 우리가 예상한 것과는 다릅니다.

항목 업데이트(Updating an entry)

매운 고추에 대해서 잘 아는 분들이라면 "Serrano"의 스코빌 지수가 실제로는 틀렸다는 것을 아셨을 겁니다. "Serrano"의 스코빌 지수는 700 이 아니라 7,000 이 맞는 수치입니다. 그럼 이 수치를 수정해 보겠습니다.

딕셔너리 항목을 업데이트하는 문법은 새로운 키(key)에 새로운 값을 할당하는 것과 동일합니다. Swift에서는 이전 값인 700을 새로운 값인 7,000으로 대체하기만 하면 됩니다.

항목 제거(Removing an entry)

딕셔너리에서 항목을 제거하는 것은 앞에 나열한 두 개의 예제와 매우 유사합니다.

값(value)을 nil로 선언하면 제거하려는 딕셔너리의 항목이 실제로 제거됩니다.

값을 nil로 선언하는 것 이외에도 removeValueForKey() 메서드를 사용해 딕셔너리의 항목을 제거할 수 있습니다.

이 예제에서는 항목의 값으로 1000을 반환했습니다. 때때로 removeValueForKey() 메서드는 항목을 제거할 때 선호하는 방법이기도 합니다. 앞으로 이 내용을 확인할 수 있습니다.