[2019.03.05]

원문 : 애플 개발 문서 Swift 5.0 Language Guide - Collection Types

컬렉션 타입(Collection Types)

Swift는 값의 컬렉션을 저장하는 3개의 기본(primary) 컬렉션 타입(collection types) 배열(array), 세트(set), 딕셔너리(dictionary)를 제공합니다. Arrays는 정렬된 값의 컬렉션입니다. Sets은 정렬되지 않은(unordered) 고유한 값의 컬렉션입니다. Dictionaries는 정렬되지 않은 연관된 키-값(key-value)의 컬렉션 입니다.

Swift에서의 배열(array), 세트(set), 딕셔너리(dictionary)는 항상 저장할 수 있는 값(vlaues)과 키(key)의 타입이 명확합니다. 이는 실수로 컬렉션에 잘못된 타입의 값을 삽입할 수 없다는 것을 의미합니다. 또한 컬렉션으로 부터 값을 가져오는 타입에 대해서 확신(confident)할 수 있다는 것을 의미합니다.

주의
Swift의 배열(array), 세트(set), 딕셔너리(dictionary) 타입들은 제네릭 컬렉션(generic collections)으로 구현되어 있습니다. 제네릭 타입과 컬렉션에 대한 자세한 정보는 Generics을 보세요.

컬렉션의 변경가능성(Mutability of Collections)

배열(array), 세트(set), 딕셔너리(dictionary)를 만들고 변수에 할당하는 경우, 만들어진 그 컬렉션은 변경가능(mutable)할 것입니다. 이는 컬렉션을 만들고나서 컬렉션에 있는 항목들을 추가하기, 삭제하기, 변경하기로 바꿀(또는 변경가능)수 있다는 것을 의미합니다. 배열(array), 세트(set), 딕셔너리(dictionary)를 상수에 할당하는 경우, 그 컬렉션은 변경불가능(mutable)하며, 크기와 내용을 바꿀 수 없습니다.

주의
컬렉션을 바꿀 필요가 없는 모든 경우에 변경불가능(mutable)한 컬렉션을 만드는 것은 좋은 습관(practice)입니다. 이렇게하는 것이 코드에 대해 이해하기 쉽게 만들고 Swift 컴파일러가 여러분이 만든 컬렉션의 성능을 최적화하는 것이 가능합니다.

배열(Arrays)

배열(array)은 정렬된 목록에 같은 타입의 값을 저장합니다. 같은 값은 배열내의 다른 위치에서 여러번 나타날수 있습니다.

주의
Swift의 Array 타입은 Foundation의 NSArray 클래스와 연결됩니다.

Foundation과 Cocoa로 Array를 사용하는 것에 대한 자세한 정보는 Bridging Between Array and NSArray를 보세요.

배열 타입 축약 문법(Array Type Shortand Syntax)

Swift 배열의 타입은 Array<Element>로 작성하며, Element는 배열에 저장할 수 있는 타입입니다. 또한 [Element]의 축약 형태로 배열의 타입을 작성할 수 있습니다. 비록 두 형식이 기능적으로 동일하지만, 축약 형태를 선호하고, 배열의 타입에 관련된 가이드에서 두루(throughout) 사용됩니다.

빈 배열 만들기(Creating an Empty Array)

초기화 문법을 사용해서 특정 타입의 비어있는 배열을 만들 수 있습니다.

var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// Prints "someInts is of type [Int] with 0 items."

someInts 변수의 타입이 초기화의 타입으로부터 [Int]로 추론되는 것을 주의합니다.

대신에, 함수 인자나 이미 타입이 있는 변수나 상수 처럼, 타입 정보를 이미 제공하는 경우, [](빈 대괄호 한쌍)으로 작성하는 빈 배열 리터럴로, 비어있는 배열을 만들 수 있습니다.

someInts.append(3)
// someInts now contains 1 value of type Int
someInts = []
// someInts is now an empty array, but is still of type [Int]

기본 값으로 배열 만들기(Creating an Array with a Default Value)

Swift의 Array 타입은 동일한 기본 값을 설정한 특정 크기의 배열을 만드는 초기화를 제공합니다. 이 초기화에 적절한 타입의 기본 값과(repeating), 새로운 배열에서 반복된 횟수 값을(count) 넘깁니다.

var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles is of type [Double], and equals [0.0, 0.0, 0.0]

두개의 배열을 함께 추가해서 배열 만들기(Creating an Array by Adding Two Arrays Together)

서로 호환되는 타입의 기존 두개의 배열을 더하기 연산자(+)를 사용해서 새로운 배열을 만들 수 있습니다. 새로운 배열의 타입은 함께 추가된 두 배열의 타입으로 추론됩니다.

var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles is of type [Double], and equals [2.5, 2.5, 2.5]

var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles is inferred as [Double], and equals [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]

배열 리터럴로 배열 만들기(Creating an Array with an Array Literal)

배열 리터럴(array literal)로 배열을 초기화 할수 있으며, 하나 이상의 값으로 배열 컬렉션을 작성하는 축약법입니다. 배열 리터럴은 값의 목록으로 작성되며, 콤마로 구분되며, 대괄호 한쌍으로 감싸져 있습니다.

[value 1, value 2, value 3]

아래 예제는 String 값을 저장하는 shoppingList 배열을 만듭니다.

var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList has been initialized with two initial items

shoppingList 변수는 문자열 값의 배열로 선언되며, [String]으로 작성됩니다. 이 특정 배열은 String의 값 타입으로 지정되었기 때문에, 오직 String 값만을 저장하도록 허용됩니다. 여기에서 shoppingList 배열은 두개의 String 값("Eggs", "Milk")으로 초기화 되며, 배열 리터럴로 작성됩니다.

주의
아래 예제에서 쇼핑 목록이 더 추가되기 때문에, shoppingList 배열은 상수(let)가 아니라 변수(var)로 선언되었습니다.

이 경우에, 배열 리터럴은 두개의 String값만을 포함하고 있습니다. shoppingList 변수의 선언(배열은 String값을 포함할 수 있음) 타입과 일치하고, 배열 리터럴의 할당은 두개의 초기화 항목들로 shoppingList 초기화하는 방법으로 허용됩니다.

Swift의 타입 추론 덕분에, 같은 타입의 값을 포함하는 배열 리터럴로 초기화하는 경우, 배열의 타입을 작성하지 않아도 됩니다. shoppingList의 초기화는 축약형식으로 작성될 수 있습니다.

var shoppingList = ["Eggs", "Milk"]

배열 리터럴에 있는 모든 값은 타입이 같이 대문에, Swift는 [String]이 shoppingList 변수에 사용할 올바른 타입인 것으로 추론할 수 있습니다.

배열 사용하고 수정하기(Accessing and Modifying an Array)

메소드와 프로퍼티, 또는 서브스크립트 문법을 사용해서 배열을 사용하고 수정합니다.

배열에 있는 항목의 갯수를 구하기 위해서, 읽기 전용(read-only)인 count 프로퍼티를 확인합니다.

print("The shopping list contains \(shoppingList.count) items.")
// Prints "The shopping list contains 2 items."

count 프로퍼티가 0과 같은지 확인하는 간단한 방법으로 Boolean isEmpty 프로퍼티를 사용합니다.

if shoppingList.isEmpty {
    print("The shopping list is empty.")
} else {
    print("The shopping list is not empty.")
}
// Prints "The shopping list is not empty."

배열의 append(_:) 메소드를 호출해서 배열의 끝부분에 새로운 항목을 추가할 수 있습니다.

shoppingList.append("Flour")
// shoppingList now contains 3 items, and someone is making pancakes

또는(alternatively), 더하기 할당 연산자(+=)를 사용해서 하나 이상의 호환가능한 항목들의 배열을 추가합니다.

shoppingList += ["Baking Powder"]
// shoppingList now contains 4 items
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// shoppingList now contains 7 items

서브스크립트 문법(subscript syntax)을 사용해서 배열로부터 값을 가져오며, 배열의 이름 바로 뒤에 대괄호 안에 원하는 값의 인덱스를 전달합니다.

var firstItem = shoppingList[0]
// firstItem is equal to "Eggs"

주의
배열에 있는 첫번째 항목은 인덱스가 1이 아니라 0입니다. Swift의 배열은 항상 제로 인덱스(zero-indexed) 입니다.

주어진 인덱스에 있는 기존 값을 변경하기 위해 서브스크립트 문법을 사용할 수 있습니다.

shoppingList[0] = "Six eggs"
// the first item in the list is now equal to "Six eggs" rather than "Eggs"

서브스크립트 문법을 사용할때, 유효한 인덱스를 지정해야 합니다. 예를 들어, 배열의 끝에 항목을 추가하기 위해shoppingList[shoppingList.count] = "Salt" 작성하면 런타임 오류가 발생할 것입니다.

또한, 한번에 값의 범위를 변경하기 위해, 서브스크립트 문법을 사용할수 있으며, 심지어는 교체하려는 값이 다른 길이를 가지고 있어도 교체할 수 있습니다. 다음에 오는 예제는 "Chocolate Spread", "Cheese", "Butter"을 "Bananas", "Apples"로 교체합니다.

shoppingList[4...6] = ["Bananas", "Apples"]
// shoppingList now contains 6 items

배열의 지정된 인덱스 위치에 항목을 삽입하기 위해, 배열의 insert(_:at:) 메소드를 호출합니다.

shoppingList.insert("Maple Syrup", at: 0)
// shoppingList now contains 7 items
// "Maple Syrup" is now the first item in the list

쇼핑 목록의 맨 앞부분에 "Maple Syrup" 값의 새로운 항목을 삽입하기 위해 insert(_:at:) 메소드를 호출하며, 0의 인덱스를 가리킵니다.

비슷하게(Similarly), remove(at:) 메소드로 배열에서 항목을 제거 합니다. 이 메소드는 특정 인덱스의 항목을 제거하고 제거된 항목을 반환합니다(반환된 값이 필요하지 않으면 무시할수 있음).

let mapleSyrup = shoppingList.remove(at: 0)
// the item that was at index 0 has just been removed
// shoppingList now contains 6 items, and no Maple Syrup
// the mapleSyrup constant is now equal to the removed "Maple Syrup" string

주의
배열의 기존 범위의 밖에 있는 인덱스에 대한 값을 사용하거나 수정하려고 하는 경우, 런타임 오류가 발생할 것입니다. 배열을 사용하기 전에 배열의 count프로퍼티를 비교해서 인덱스가 유효한지 검사할 수 있습니다. 배열은 0으로부터 인덱스되기 때문에, 배열에서 유효한 마지막 인덱스는 count - 1입니다 - 하지만, count가 0일때(배열이 비어있음을 의미), 유효한 인덱스는 없습니다.

배열에서 항목이 제거될때, 배열의 모든 틉새(gaps)는 닫히게되고, 인덱스 0에 있는 값은 또다시 "Six eggs"와 같습니다.

firstItem = shoppingList[0]
// firstItem is now equal to "Six eggs"

배열에서 마지막 항목을 제거하길 원하는 경우에, remove(at:) 메소드를 사용하기보다는 배열의 count 프로퍼티를 조회할 필요가 없는, removeLast() 메소드를 사용합니다. remove(at:) 메소드 처럼, removeLast()는 제거된 항목을 반환합니다.

let apples = shoppingList.removeLast()
// the last item in the array has just been removed
// shoppingList now contains 5 items, and no apples
// the apples constant is now equal to the removed "Apples" string

배열 반복하기(Iterating Over an Array)

for-in 반복문으로 배열에 있는 모든 값의 설정을 반복할 수 있습니다.

for item in shoppingList {
    print(item)
}
// Six eggs
// Milk
// Flour
// Baking Powder
// Bananas

각 항목의 값 뿐만아니라 정수형 인덱스가 필요한 경우, 배열을 반복하기 위해 enumerated() 메소드를 사용합니다. 배열에 있는 각 항목에 대해, enumerated() 메소드는 정수와 항목(item)으로 구성된 튜플을 반환합니다. 정수는 0에서 시작하고 각 항목에 대해 하나씩 올라갑니다. 배열 전체를 나열하는 경우, 이러한 정수들은 항목의 인덱스와 일치합니다. 반복의 일부분으로 임수 상수나 변수로 튜플을 분해 할 수 있습니다.

for (index, value) in shoppingList.enumerated() {
    print("Item \(index + 1): \(value)")
}
// Item 1: Six eggs
// Item 2: Milk
// Item 3: Flour
// Item 4: Baking Powder
// Item 5: Bananas

for-in 반복문에 대한 자세한 사항은, For-in Loops를 보세요.

세트(Sets)

세트(set)는 컬렉션에서 정의된 순서가 없이 같은 타입의 고유한(distinct) 값을 저장합니다. 항목들의 순서가 중요하지 않거나, 하나의 항목이 전체에서 한번만 필요한 경우에, 배열 대신에 세트(set)를 사용할 수 있습니다.

주의
Swift의 Set 타입은 Foundation의 NSSet 클래스와 연결되어 있습니다.

Foundation과 Cocoa로 Set을 사용하는 것에 대한 자세한 정보는 Bridging Between Set and NSSet을 보세요.

세트 타입에 대한 해쉬 값(Hash Values for Set Types)

하나의 타입을 세트(set)에 저장하기 위해서 반드시 hashable이어야 합니다 - 즉, 타입은 반드시 자체적으로 해쉬 값(hash value)을 계산하는 방법을 제공해야합니다. a === b 인 경우에, a.hasValue == b.hashValue인 것 처럼, 하나의 해쉬 값은 모든 객체에 대해 같은지 비교하는 Int값입니다.

Swift의 모든 기본 타입(String, Int, Double, Bool)은 기본적으로 hashable이고, 세트(set) 값 타입 또는 딕셔너리(dictionary)의 키(key) 타입으로 사용될 수 있습니다. 연관된 값(Enumeration에서 설명됨)이 없는 열거형의 case 값은 기본적으로 hashable입니다.

주의
Swift의 표준 라이브러리로부터 Hashable 프로토콜을 준수하도록 만들어, 세트 값 타입 또는 딕셔너리 키 타입으로 자신의 사용자정의 타입을 사용할 수 있습니다. 타입이 Hashable 프로토콜을 준수하도록 하기 위해 반드시 gattable인 Int 프로퍼티 hashValue를 제공해야 합니다. 그 값은 타입의 hashValue프로퍼티에 의해 반환된 값은 필동일한 프로그램의 다른 실행이나 다른 프로그램에서 같지 않아도 됩니다.

Hashable 프로토콜이 Equatable을 준수하기 때문에, 이를 준수하는 타입은 동등 연산자(==)를 반드시 구현해야 합니다. Equatable 프로토콜은 동등한 관계가 되도록 하기 위해서 == 구현이 필요합니다. 즉, ==의 구현은 a, b, c 모든 값에 대해서, 반드시 다음 3가지 조건을 충족(satisfy)해야 합니다.

  • a == a 재귀(Reflexivity)
  • a == b는 b == a를 의미. 대칭(Symmetry)
  • a == b && b == c는 a == c를 의미. 이행성(Transitivity)

세트 타입 문법(Set Type Syntax)

Swift의 세트(set)의 타입은 Set<Element>로 작성하며, Element는 세트(set)에 저장가능한 타입입니다. 배열과는 다르게, 세트에는 축약 형식이 없습니다.

빈 세트 만들고 초기화하기(Creating and Initializing an Empty Set)

초기화 문법을 사용해서 특정 타입의 비어 있는 세트(set)를 만들수 있습니다.

var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
// Prints "letters is of type Set<Character> with 0 items."

주의
letters 변수의 타입은 초기화 타입으로부터 Set<Character>이 되도록 추론됩니다.

또는(alternatively), 함수의 인자나 이미 타입이 있는 변수나 상수 처럼, 이미 타입 정보가 제공되는 경우, 비어있는 배열로 비어있는 세트를 만들 수 있습니다.

letters.insert("a")
// letters now contains 1 value of type Character
letters = []
// letters is now an empty set, but is still of type Set<Character>

배열 리터럴로 세트 만들기(Creating a Set with an Array Literal)

또한 하나 이상의 값을 세트 컬렉션을 만드는 축약 방법으로 배열 리터럴로 세트를 초기화 할수 있습니다.

아래 예제는 String 값을 저장하기 위해 favoriteGenres 세트(set)를 만듭니다.

var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGenres has been initialized with three initial items

favoriteGenres 변수는 String 값의 세트(set)로 선언되었으며, Set<String>으로 작성됩니다. 특정 세트는 String의 값 타입으로 지정되었기 때문에, String 값만 저장하도록 허용됩니다. 여기에서 favoriteGenres 세트(set)는 배열 리터럴로 작성된 3개의 String 값("Rock", "Classical", "Hip hop")으로 초기화됩니다.

주의
예제 아래에서 항목이 추가되고 제거되기 때문에, favoriteGenres 세트는 상수(let)가 아닌 변수(`var)로 선언됩니다.

세트(set) 타입은 배열 리터럴 단독으로 추론될 수 없으며, Set 타입은 반드시 명시적으로 선언되어야 합니다. 하지만 Swift의 타입 추론 때문에, 하나의 타입만을 포함하는 배열 리터럴로 초기화하는 경우에, 세트(set) 요소들의 타입을 작성하지 않아도 됩니다. favoriteGenres의 초기화는 축약 형힉으로 작성될 수 있습니다.

var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]

배열 리터럴에 있는 모든 값은 동일한 타입이기 때문에, Swift는 Set<String>이 favoriteGenres 변수로 사용하는 정확한 타입이라고 추론할수 있습니다.

세트 사용하고 수정하기(Accessing and Modifying a Set)

세트(set)의 메소드와 프로퍼티로 사용하고 수정합니다.

세트에 있는 항목의 갯수를 구하기 위해, 읽기 전용인 count 프로퍼티를 확인합니다.

print("I have \(favoriteGenres.count) favorite music genres.")
// Prints "I have 3 favorite music genres."

count 프로퍼티가 0과 같은지 확인하는 축약법으로 Boolean isEmpty 프로퍼티를 사용합니다.

if favoriteGenres.isEmpty {
    print("As far as music goes, I'm not picky.")
} else {
    print("I have particular music preferences.")
}
// Prints "I have particular music preferences."

세트의 insert(_:) 메소드를 호출해서 세트에 새로운 항목을 추가할 수 있습니다.

favoriteGenres.insert("Jazz")
// favoriteGenres now contains 4 items

세트의 remove(_:) 메소드를 호출해서 세트에서 항목을 제거할수 있으며, 세트의 멤버인 경우에 제거된 값을 반환하거나 세트에 포함되어 있지 않은 경우에 nil을 반환합니다. 또는(alternatively), 세트에 있는 모든 항목들은 removeAll() 메소드로 제거될 수 있습니다.

if let removedGenre = favoriteGenres.remove("Rock") {
    print("\(removedGenre)? I'm over it.")
} else {
    print("I never much cared for that.")
}
// Prints "Rock? I'm over it."

세트가 특정 항목을 포함하고 있는지 검사하기 위해서 contains(_:) 메소드를 사용합니다.

if favoriteGenres.contains("Funk") {
    print("I get up on the good foot.")
} else {
    print("It's too funky in here.")
}
// Prints "It's too funky in here."

세트 반복하기(Iterating Over a Set)

세트에 있는 값들을 for-in 반복문으로 반복할 수 있습니다.

for genre in favoriteGenres {
    print("\(genre)")
}
// Classical
// Jazz
// Hip hop

for-in 반복문에 대한 자세한 것은 For-in Loops를 보세요.

Swift의 Set 타입은 정의된 순서가 없습니다. 특정 순서로 세트의 값들을 반복하기 위해서, sorted() 메소드를 사용하며, <연산자를 사용해서 정렬되는 배열처럼 세트의 요소들을 반복합니다.

for genre in favoriteGenres.sorted() {
    print("\(genre)")
}
// Classical
// Hip hop
// Jazz

세트 연산 처리하기(Performing Set Operations)

2개의 세트를 함께 결합하기, 2개의 세트에 공통으로 가지는 값을 결정하기, 또는 2개의 세트가 전부 또는 일부를 포함하는지 또는 같은 값이 없는지 처럼, 기본 세트 연산을 효율적으로 수행할 수 있습니다.

기본 세트 연산(Fundamental Set Operations)

아래 그림은 2개의 세트(a, b)로 다양한 세트의 연산의 결과를 그림자 영역으로 표현한것입니다.

  • intersection(_:) 메소드는 2개의 세트에서 공통 값만으로 새로운 세트를 만들기 위해 사용합니다.
  • symmetricDifference(_:) 메소드는 2개의 세트에서가 아니라 각각의 세트에만 있는 값으로 새로운 세트를 만들기 위해 사용합니다.
  • union(_:) 메소드는 2개의 세트에 있는 모든 값으로 새로운 세트를 만들기 위해 사용합니다.
  • subtractin(_:) 메소드는 특정 세트에 있는 값으로 새로운 세트를 만들기 위해 사용합니다.
let oddDigits: Set = [1, 3, 5, 7, 9]
let evenDigits: Set = [0, 2, 4, 6, 8]
let singleDigitPrimeNumbers: Set = [2, 3, 5, 7]

oddDigits.union(evenDigits).sorted()
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
oddDigits.intersection(evenDigits).sorted()
// []
oddDigits.subtracting(singleDigitPrimeNumbers).sorted()
// [1, 9]
oddDigits.symmetricDifference(singleDigitPrimeNumbers).sorted()
// [1, 2, 9]

세트의 멤버인지와 같은지를 비교(Set Membership and Equality)

아래 그림은 3개의 세트(a, b, c)에서 세트 간에 공유된 요소들을 중첩된 영역으로 표현하였습니다. 세트 a 는 b의 모든 요소가 a에 포함되기 때문에 세트 b의 상위세트(superset) 입니다. 세트 b는 b의 모든 요소가 a에 포함되기 때문에 세트 a의 하위세트(subset)입니다. 세트 b와 세트 c는 공통으로 공유하는 요소가 없기 때문에, 따로 분리(disjoint)되어 있습니다.

  • 같음(is equal) 연산자(==)를 2개의 세트가 모두 값은 값을 포함하고 있는지 결정하기 위해 사용합니다.
  • isSubset(of:) 메소드를 세트의 모든 값들이 지정된 세트에 포함되는지 결정하기 위해 사용합니다.
  • isSuperset(of:) 메소드를 하나의 세트가 지정된 세트의 모든 값을 포함하는지 결정하기 위해 사용합니다.
  • isStrictSubset(of:) 또는 isStrictSuperset(of:) 메소드는 세트가 하위세트 또는 상위세트인지 결정하기 위해 사용합니다.
  • isDisjoint(with:) 메소드는 2개의 세트가 공통적인 값이 없는지 결정하기 위해 사용합니다.
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]

houseAnimals.isSubset(of: farmAnimals)
// true
farmAnimals.isSuperset(of: houseAnimals)
// true
farmAnimals.isDisjoint(with: cityAnimals)
// true

딕셔너리(Dictionaries)

딕셔너리(dictionary)는 정의된 순서없이 같은 타입의 키(key)와 같은 타입의 값(value)으로 연관(associations)된 것을 저장하는 컬랙션입니다. 각 값은 고유한 키(key)로 연관되며, 딕셔너리에서 값을 식별하는 동작을 합니다. 배열에 있는 항목들과는 다르게, 딕셔너리에 있는 항목들은 지정된 순서가 없습니다. 식별자를 기반으로 값을 찾을 필요가 있을대 딕셔너리를 사용하며, 실생활에서 사전으로 특정 단어에 대한 정의를 찾는 것과 거의 같은 방법입니다.

주의
Swift의 Dictionary 타입은 Foundation의 NSDictionary클래스와 연관되어 있습니다.

Foundation과 Cocoa에서의 Dictionary 사용에 대한 자세한 정보는 Bridging Between Dictionary and NSDictionary를 보세요.

딕셔너리 타입 축약 문법(Dictionary Type Shorthand Syntax)

Swift 딕셔너리의 타입은 Dictionary<Key, Value>로 작성되며, Key는 딕셔너리 키로 저장할수 있는 값의 타입이고, Value는. 이러한 키(keys)로 저장되는 값의 타입입니다.

주의
딕셔너리(dictionary) Key 타입은 세트(set)의 값 타입처럼, 반드시 Hashable 프로토콜을 준수해야 합니다.

또한 [Key, Value]로 축약 형식으로 딕셔너리의 타입을 작성할 수 있습니다. 비로 2가지 형식이 기능적으로 동일할지라도, 축향 형식이 선호되고 딕셔너리 타입과 관련된 가이드에서 전반적으로 사용됩니다.

빈 딕셔너리 만들기(Creating an Empty Dictionary)

배열 처럼, 초기화 문법을 사용해서 특정 타입의 비어있는 Dictionary를 만들 수 있습니다.

var namesOfIntegers = [Int: String]()
// namesOfIntegers is an empty [Int: String] dictionary

이 예제는 사람이 읽을수 있는 정수 값의 이름을 저장하기 위해 [Int: String] 타입의 비어있는 딕셔너리를 만듭니다. 키(keys)는 Int 타입이고, 값(values)은 String 타입입니다.

문맥상(context) 타입 정보를 이미 제공하는 경우, 빈 딕셔너리 리터럴로 빈 딕셔너리를 만들수 있으며, [:]로 작성됩니다(대괄호 한쌍 안에 콜론)

namesOfIntegers[16] = "sixteen"
// namesOfIntegers now contains 1 key-value pair
namesOfIntegers = [:]
// namesOfIntegers is once again an empty dictionary of type [Int: String]

딕셔너리 리터럴로 딕셔너리 만들기(Creating Dictionary with a Dictionary Literal)

또한 딕셔너리 리터럴(dictionary literal)로 딕셔너리 초기화할 수 있으며, 이전의 배열 리터럴과 비슷한 문법입니다. 딕셔너리 리터럴은 하나 이상의 키-값 쌍(key-value pairs)으로 Dictionary 컬렉션으로 작성하는 축약 방법입니다.

키-값 쌍(key-value pairs)은 키(key)와 값(value)의 조합입니다. 딕셔너리 리터럴에서, 각 키-값 쌍에서의 키와 값은 콜론(:)으로 구분됩니다. 키-값 쌍은 목록으로 작성되며, 콤마로 구분되며, 대괄호의 쌍으로 감싸집니다.

[key 1: value 1, key 2: value 2, key 3: value 3]

아래 예제에서 국제 공항의 이름을 저장하기 위해서 딕셔너리를 만듭니다. 딕셔너리에서, 키는 3 글자(three-letter)의 국제공항 운송협회(International Air Transport Association) 코드이고, 값은 공항 이름입니다.

var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

ariports 딕셔너리는 [String: String] 타입으로 선언되며, Dictionary는 String 타입의 키와 String타입의 값입니다를 의미합니다.

주의
아래 예제에서 딕셔너리에 공항이 더 추가되기 때문에 airports 딕셔너리는 상수(let)가 아니라 변수(var)로 선언됩니다.

airports 딕셔너리는 두개의 키-값 쌍을 포함하는 딕셔너리 리터럴로 초기화됩니다. 첫번째 쌍은 "YYZ"의 키와 "Toronto Pearson"의 값입니다. 두번재 쌍은 "DUB"의 키와 "Dublin"의 값입니다.

딕셔너리 리터럴은 두개의 String: String 쌍을 포함합니다. 키-값 타입은 airports 변수 선언(String키와 String인 딕셔너리)의 타입과 일치하고, 두개의 초기화 항목으로 airports 딕셔너리의 초기화하는 방법으로 딕셔너리 리터럴의 할당을 허용됩니다.

배열과 마찬가지로, 키와 값이 일관된(consistent) 타입의 딕셔너리 리터럴로 초기화하는 경우에, 딕셔너리의 타입을 작성하지 않아도 됩니다. airports의 초기화는 짧게 작성할 수 있습니다.

var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

리터럴에 있는 모든 키(keys)는 각각 같은 타입이고 마찬가지로 모든 값이 각각 같은 타입이기 때문에, Swift는 [String: String]이 airports딕셔너리 사용에 대해 올바른 타입이라 추론할 수 있습니다.

딕셔너리 사용하고 수정하기(Accessing and Modifying a Dictionary)

딕셔너리의 메소드와 프로퍼티, 또는 서브스크립트 문법을 통해서 사용하고 수정합니다.

배열과 마찬가지로, 읽기 전용 count 프로퍼티를 확인해서 Dictionary의 항목의 갯수를 구합니다.

print("The airports dictionary contains \(airports.count) items.")
// Prints "The airports dictionary contains 2 items."

count 프로퍼티가 0과 같은지 확인하기 위해 Boolean isEmpty 프로퍼티를 사용합니다.

if airports.isEmpty {
    print("The airports dictionary is empty.")
} else {
    print("The airports dictionary is not empty.")
}
// Prints "The airports dictionary is not empty."

서브스크립트 문법으로 딕셔너리에 새로운 항목을 추가할 수 있습니다. 적절한 타입의 새 키를 서브스크립트 인덱스로 사용하고, 적절한 타입의 새 값을 할당합니다.

airports["LHR"] = "London"
// the airports dictionary now contains 3 items

또한, 특정 키와 연관된 값을 변경하기 위해서 서브스크립트 문법을 사용합니다.

airports["LHR"] = "London Heathrow"
// the value for "LHR" has been changed to "London Heathrow"

특정 키에 대한 값을 설정하거나 업데이트 하기 위해 딕셔너리의 updateValue(_:forKey:) 메소드를 사용합니다. 위의 서브스크립트 예제처럼, updateValue(_:forKey:) 메소드는 키가 존재하지 않으면 값을 설정하거나, 키가 존재하면 값을 업데이트 합니다. 하지만, 서브스크립트와는 다르게, updateValue(_:forKey:) 메소드는 업데이트를 수행하고나서 예전(old) 값을 반환합니다. 이것으로 업데이트가 발생했는지 확인이 가능합니다.

updateValue(_:forKey:) 메소드는 딕셔너리의 값 타입의 옵셔널 값을 반환합니다. String 값을 저장하는 딕셔너리를 예를 들어, 그 메소드는 String? 타입의 값 또는 옵셔널 String을 반환합니다. 이 옵셔널 값은 업데이트하기 전에, 기존 값이 있으면 예전(old)값을 반환하고, 기존 값이 없는 경우에 nil을 반환합니다.

if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
    print("The old value for DUB was \(oldValue).")
}
// Prints "The old value for DUB was Dublin."

또한 딕셔너리로부터 특정 키에 대한 값을 가져오기 위해 서브스크립트 문법을 사용합니다. 존재하지 않는 키에 대해 요청하는 것이 가능하기 때문에, 딕셔너리의 서브스크립트는 딕셔너리의 값 타입의 옵셔널 값을 반환합니다. 딕셔너리가 요청한 키에 대한 값을 포함하는 경우, 서브스크립트는 키에 대해 기존 값을 포함하는 옵셔널 값을 반환합니다. 그렇지 않은 경우에, 서브스크립트는 nil을 반환합니다:

if let airportName = airports["DUB"] {
    print("The name of the airport is \(airportName).")
} else {
    print("That airport is not in the airports dictionary.")
}
// Prints "The name of the airport is Dublin Airport."

딕셔너리의 키-값 쌍을 제거하기 위해 키에 대한 값을 nil로 할당하는 서브스크립트 문법을 사용할 수 있습니다.

airports["APL"] = "Apple International"
// "Apple International" is not the real airport for APL, so delete it
airports["APL"] = nil
// APL has now been removed from the dictionary

또는, removeValue(forKey:)메소드로 딕셔너리에서 키-값 쌍을 제거합니다. 이 메소드는 값이 전재하는 경우에 키-값 쌍을 제거하고 제거된 값을 반환하며, 또는 값이 없는 경우에 nil을 반환합니다.

if let removedValue = airports.removeValue(forKey: "DUB") {
    print("The removed airport's name is \(removedValue).")
} else {
    print("The airports dictionary does not contain a value for DUB.")
}
// Prints "The removed airport's name is Dublin Airport."

딕셔너리 반복하기(Iterating Over a Dictionary)

for-in 반복문으로 딕셔너리에 있는 키-값 쌍을 반복할수 있습니다. 딕셔너리에 있는 각 항목은 (key, value) 튜플로 반환되고, 반복문의 일부분으로, 튜플의 멤버로 임시 상수나 변수로 분해(decompose)할 수 있습니다.

for (airportCode, airportName) in airports {
    print("\(airportCode): \(airportName)")
}
// YYZ: Toronto Pearson
// LHR: London Heathrow

for-in 반복문에 대해 자세한 것은 For-in Loops를 보세요.

keys와 values 프로퍼티를 사용해서 딕셔너리의 키나 값의 컬렉션을 반복해서 가지고 올수 있습니다.

for airportCode in airports.keys {
    print("Airport code: \(airportCode)")
}
// Airport code: YYZ
// Airport code: LHR

for airportName in airports.values {
    print("Airport name: \(airportName)")
}
// Airport name: Toronto Pearson
// Airport name: London Heathrow

Array 인스턴스를 사용하는 API로 딕셔너리의 키(keys)나 값(values)을 사용해야 하는 경우에, keys나 values 프로퍼티로 새로운 배열을 초기화 합니다.

let airportCodes = [String](airports.keys)
// airportCodes is ["YYZ", "LHR"]

let airportNames = [String](airports.values)
// airportNames is ["Toronto Pearson", "London Heathrow"]

Swift의 Dictionary 타입은 정의된 순서가 없습니다. 딕셔너리에서 특정 순서로 키(keys)나 값(values)을 반복하기 위해서, keys나 values프로퍼티에서 sorted() 메소드를 사용합니다.

'Swift > Language Guide' 카테고리의 다른 글

컬렉션 타입(Collection Types)  (0) 2019.03.05
문자열과 문자(Strings and Characters)  (0) 2019.02.28
기본 연산자(Basic Operators)  (0) 2019.02.26
기초(The Basics)  (0) 2019.02.12
Advanced Operators  (0) 2018.09.18
Access Control  (0) 2018.09.18
Memory Safety  (0) 2018.09.18
Automatic Reference Counting  (0) 2018.09.18
Generics  (0) 2018.09.18
Posted by 까칠코더

댓글을 달아 주세요