티스토리 뷰

3. Dictionary

Dictionary 란, 사전과 유사한 형태로 데이터를 저장하는 collection 으로 key-value 쌍을 저장합니다. 이때 key 는 해당 collection 에서 유일한 값이어야 합니다. 특징은 다음과 같습니다.

 

- 정렬되지 않은 상태로 저장 (Unordered Collection)

- 한 dictionary 에 저장되는 데이터 타입은 모두 동일 (Single Type)

 

Dictionary 를 생성하는 방법은 리터럴과 타입 지정이 있습니다.

// Dictionay Literal
// 문법
// [key: value, key: value, ...]
var dict = ["A": "Apple", "B": "Banana"]
// 빈 dictionary
dict = [:]

// Dictionary Type
// 문법
// Dictionary<K, V>
// [K:V] (단축형)
let dict1: Dictionary<String, Int>
let dict2: [String:Int]

 

Dictionary 의 기본 사용법은 다음과 같습니다.

// Creating a Dictionary
let words = ["A": "Apple", "B": "Banana", "C": "City"]

let emptyDict: [String: String] = [:]
let emptyDict2 = [String:String]()
let emptyDict3 = Dictionary<String, String>()

// Inspecting a Dictionary
words.count    // 결과: 3
words.isEmpty  // 결과: false

// Accessing Keys and Values
// key 를 통해서 값에 접근, String? 타입을 리턴
words["A"]      // 결과: "Apple"
words["Apple"]  // 결과: nil

let a = words["E"]  // 결과: nil
// 키와 연결된 값이 있으면 그 값을 없다면 default 값을 리턴
let b = words["E", default: "Empty"]  // 결과: "Empty"

for k in words.keys.sorted() {
    print(k)
}
// 결과
A
B
C

for v in words.values {
    print(v)
}
// 결과
Apple
City
Banana

// Dictionary 의 키와 값을 배열로 전환
let keys = Array(words.keys)      // 결과: ["A", "C", "B"]
let values = Array(words.values)  // 결과: ["Apple", "City", "Banana"]

 

Dictionary 에 새로운 요소를 추가, 삭제하는 방법을 알아보겠습니다.

// Adding Keys and Values

// - 하나의 요소 저장
var ws = [String:String]()
ws["A"] = "Apple"
ws["B"] = "Banana"

ws.count  // 결과: 2
ws        // 결과: ["A": "Apple", "B": "Banana"]

// - 이미 딕셔너리에 있는 키에 값을 저장하면 값이 수정됨
ws["B"] = "Ball"
ws.count  // 결과: 2
ws        // 결과: ["A": "Apple", "B": "Ball"]

// - 위와 같은 작업을 메소드를 사용해서 수행
// 존재하지 않은 키와 값을 추가하면 새로운 요소 추가
// 이미 존재하는 키와 값을 추가하면 기존 키의 값을 수정
// = upsert
ws.updateValue("City", forKey: "C")    // 반환 값: nil
ws.updateValue("Circle", forKey: "C")  // 반환 값: "City"

// Removing Keys and Values
ws  // 결과: ["C": "Circle", "B": "Ball", "A": "Apple"]
ws["B"] = nil
ws  // 결과: ["C": "Circle", "A": "Apple"]

// 존재하지 않은 키를 삭제하는 경우에는 아무 동작도 하지 않음
ws["Z"] = nil

// 키와 관련된 값을 삭제 후 해당 값을 리턴
ws.removeValue(forKey: "A")  // 반환 값: "Apple"
ws.removeValue(forKey: "A")  // 반환 값: nil

// 전체 요소를 삭제하기
ws.removeAll()  // 반환 값: [:]

 

Dictionary 를 비교, 검색하는 방법을 알아보겠습니다.

// Comparing Dictionaries
let aa = ["A": "Apple", "B": "Banana", "C": "City"]
let bb = ["A": "Apple", "C": "City", "B": "Banana"]

// 저장되어 있는 키-값이 동일한지 비교 (순서 상관 없음)
aa == bb  // 결과: true
aa != bb  // 결과: false

// 대소문자 구분 없이 비교하는 방법
// 아래 코드는 잘못된 코드
//aa.elementsEqual(bb) { (lhs, rhs) -> Bool in
//    return lhs.key.caseInsensitiveCompare(rhs.key) == .orderedSame && lhs.value.caseInsensitiveCompare(rhs.value) == .orderedSame
//}

// 키를 정렬한 후에 비교해야 함
let aKeys = aa.keys.sorted()  // ["A", "B", "C"]
let bKeys = bb.keys.sorted()  // ["A", "B", "C"]

aKeys.elementsEqual(bKeys) { (lhs, rhs) -> Bool in
    guard lhs.caseInsensitiveCompare(rhs) == .orderedSame else {
        return false
    }
    
    guard let lv = aa[lhs], let rv = bb[rhs], lv.caseInsensitiveCompare(rv) == .orderedSame else {
        return false
    }
    
    return true
}
// 결과: true


// Finding Elements
ws = ["A": "Apple", "B": "Banana", "C": "City"]

let c: ((String, String)) -> Bool = {
    $0.0 == "B" || $0.1.contains("i")
}
ws.contains(where: c)  // 결과: true

// 실행할 때마다 결과가 다를 수 있음 (Dictionary 는 순서가 없기 때문에)
let r = ws.first(where: c)
r?.key    // 결과: "B"
r?.value  // 결과: "Banana"

ws.filter(c)  // 결과: ["C": "City", "B": "Banana"]

 

4. Set

Set 은 집합을 나타내는 Collection 으로 다음과 같은 특징을 가집니다.

 

- 정렬 순서보다 검색 속도가 중요한 경우 배열 대신 사용 (Hashing 알고리즘 사용)

- 정렬되지 않으며 인덱스를 사용하지도 않음 (Unordered Collection)

- 동일한 형식의 요소를 저장 (Single Type)

- 동일한 값을 하나만 저장, 중복 불가 (Single Unique Value)

 

Set 을 생성하는 방법은 다음과 같습니다.

// Set Literal
// 배열과 동일한 리터럴을 사용함
let setLiteral = [1, 2, 2, 3, 3, 3]
// 형식 추론에서는 항상 Array 로 추론됨
setLiteral.count  // 결과: 6

// Set Type
// 문법
// Set<T>
// 초기 값을 입력하는 경우 <T> 는 생략 가능
let set: Set<Int> = [1, 2, 2, 3, 3, 3]
set.count  // 결과: 3

// Inspecting a Set
set.count    // 결과: 3
set.isEmpty  // 결과: false

// Testing for Membership
// 요소가 포함되어 있는지 확인
set.contains(1)  // 결과: true

 

Set 에 요소를 추가, 삭제 하는 방법을 알아보겠습니다.

// Adding and Removing Elements
var words = Set<String>()

// - 요소를 추가하고 결과를 튜플로 리턴함 (요소 추가 결과, 추가된 요소)
var insertResult = words.insert("Swift")  // 반환 값: (inserted true, memberAfterInsert "Swift")
insertResult.inserted           // true
insertResult.memberAfterInsert  // "Swift"

insertResult = words.insert("Swift")  // 반환 값: (inserted false, memberAfterInsert "Swift")
insertResult.inserted           // false
insertResult.memberAfterInsert  // "Swift"

// upsert 방식으로 동작, 작업의 결과를 String? 으로 리턴
var updateResult = words.update(with: "Swift")
updateResult  // 결과: "Swift"

updateResult = words.update(with: "Apple")
updateResult  // 결과: nil

// Set 은 Hash 값이 다르면 다른 문자로 인식하고 처리!!

var value = "Swift"
// Hash 값 확인
value.hashValue

updateResult = words.update(with: value)
updateResult  // 결과: "Swift"

value = "Hello"
value.hashValue

updateResult = words.update(with: value)
updateResult  // 결과: nil

 

Set 을 비교하는 방법을 알아보겠습니다.

// Comparing Sets
var a: Set = [1, 2, 3, 4, 5, 6, 7, 8, 9]
var b: Set = [1, 3, 5, 7, 9]
var c: Set = [2, 4, 6, 8, 10]
let d: Set = [1, 7, 5, 9, 3]

a == b  // 결과: false
a != b  // 결과: true

b == d  // 결과: true

// 두 컬랙션에 저장된 요소를 순서대로 비교하므로 결과는 실행할 때마다 다름
b.elementsEqual(d)

// 집합 비교
// 부분 집합 비교
a.isSubset(of: a)        // 결과: true
a.isStrictSubset(of: a)  // 결과: false

b.isSubset(of: a)        // 결과: true
b.isStrictSubset(of: a)  // 결과: true

d.isSubset(of: a)        // 결과: true
d.isStrictSubset(of: a)  // 결과: true

// 상위 집합 비교
a.isSuperset(of: a)        // 결과: true
a.isStrictSuperset(of: a)  // 결과: false

a.isSuperset(of: b)        // 결과: true
a.isStrictSuperset(of: b)  // 결과: true

a.isSuperset(of: c)        // 결과: false (a 에 없는 값을 c 가 가지도 있으므로)
a.isStrictSuperset(of: c)  // 결과: false

// 교집합 확인
// 교집합 = false, 서로소 집합 = true
a.isDisjoint(with: b)  // 결과: false
a.isDisjoint(with: c)  // 결과: false
b.isDisjoint(with: c)  // 결과: true

 

Set 은 주로 집합 연산을 할 때 많이 사용이 됩니다.

// Combining Sets
// 집합 연산

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [1, 3, 5, 7, 9]
c = [2, 4, 6, 8, 10]

// 합집합 구하기
var result = b.union(c)  // {6, 3, 8, 2, 10, 5, 1, 9, 7, 4}
result = b.union(a)      // {1, 3, 2, 7, 6, 8, 5, 9, 4}

b.formUnion(c) // 직접 b set 을 변경함
b  // {6, 3, 8, 2, 10, 5, 1, 9, 7, 4}

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [1, 3, 5, 7, 9]
c = [2, 4, 6, 8, 10]

// 교집합 구하기
result = a.intersection(b)  // {1, 5, 3, 7, 9}
result = c.intersection(b)  // Set([])

// 원본을 변경하는 교집합 구하기
a.formIntersection(b)
a  // {9, 1, 5, 3, 7}

b.formIntersection(c)
b  // Set([])

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [1, 3, 5, 7, 9]
c = [2, 4, 6, 8, 10]

// 여집합 구하기
result = a.symmetricDifference(b)  // {2, 8, 6, 4}
result = c.symmetricDifference(b)  // {6, 5, 8, 7, 10, 2, 1, 9, 4, 3}

a.formSymmetricDifference(b)  // {2, 8, 6, 4}

a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
b = [1, 3, 5, 7, 9]
c = [2, 4, 6, 8, 10]

// 차집합 구하기
result = a.subtracting(b)  // {4, 8, 2, 6}
a.subtract(b) // 원본 set 변경하기

 

5. Iterating Collections

Collection 열거란, Collection 에 저장된 모든 요소를 대상으로 반복적인 작업을 수행한다는 것으로 2가지 방법이 있습니다.

// for-in
// for element in collection {
//     statements
// }

print("Array", "================")
let arr = [1, 2, 3]
for num in arr {
    print(num)
}

print("Set", "================")
let set: Set = [1, 2, 3]
for num in set {
    print(num)
}

print("Dictionary", "================")
let dict = ["A": 1, "B": 2, "C": 3]
for (key, value) in dict {
    print(key, value)
}

// 결과
Array ================
1
2
3
Set ================
1
2
3
Dictionary ================
A 1
C 3
B 2
// forEach
// 반복적으로 실행하는 코드를 클로저 파라미터로 받음
// 이 파라미터는 하나의 파라미터를 가지면 값을 리턴하지는 않음

print("Array", "================")
let arr2 = [1, 2, 3]
arr2.forEach { (num) in
    print(num)
}

print("Set", "================")
let set2: Set = [1, 2, 3]
set2.forEach { (num) in
    print(num)
}

print("Dictionary", "================")
let dict2 = ["A": 1, "B": 2, "C": 3]
dict2.forEach { (elem) in
    print(elem.key, elem.value)
}

// 결과
Array ================
1
2
3
Set ================
2
3
1
Dictionary ================
B 2
C 3
A 1

 

두가지 방법의 차이점은 다음과 같습니다.

 

1. for-in 문에서만 break, continue 사용 가능

2. for-in 문에 포함된 return 문은 반복문이 포함된 코드 블록이 바로 종료되지만 forEach 문에 포함된 return 문은 해당 클로저의 실행만을 멈출 뿐 외부 및 반복 횟수에 영향을 주지 않음

func withForIn() {
    print(#function)
    let arr = [1, 2, 3]
    for num in arr {
        print(num)
        return
    }
}

func withForeach() {
    print(#function)
    let arr = [1, 2, 3]
    arr.forEach { (num) in
        print(num)
        return
    }
}

withForIn()
withForeach()

// 결과
withForIn()
1
withForeach()
1
2
3
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함