Swift 이것까지 알아야해? 응 알아야해.(배열, 딕셔너리, 세트 완벽 이해 3탄)

작성일 :

Swift 고급자를 위한 심화 가이드: 배열, 딕셔너리, 세트 완벽 이해

Swift는 애플 생태계에서 강력하고 직관적인 프로그래밍 언어로 자리잡고 있습니다. 고급 개발자라면 배열(Array), 딕셔너리(Dictionary), 세트(Set)와 같은 기본 컬렉션 타입에 대한 기본 지식뿐만 아니라 이들을 효율적으로 활용하고, 고급 기능들을 최대한 활용하는 방법을 알아야 합니다. 이번 가이드에서는 이러한 컬렉션 타입을 더 깊이 이해하고, 실무에서 유용하게 쓸 수 있는 고급 기능들을 소개합니다.

배열 (Array)

배열의 고급 사용법

배열은 동일한 타입의 값들을 순서대로 저장하는 컬렉션 타입입니다. 배열을 더 효율적으로 사용하는 방법을 알아봅시다.

배열 슬라이싱

배열의 일부를 쉽게 추출할 수 있습니다. 슬라이싱은 데이터 분석 및 부분 배열 조작에 유용합니다.

swift
let numbers = [1, 2, 3, 4, 5, 6]
let slice = numbers[2...4] // [3, 4, 5]

슬라이싱된 배열은 ArraySlice 타입을 가지며, 이를 통해 원본 배열의 메모리를 공유합니다. 이 점을 유념하여 메모리 사용을 최적화할 수 있습니다.

고차 함수 사용

고차 함수 map, filter, reduce는 배열을 조작하는 데 강력한 도구입니다. 특히 데이터 변환 및 필터링 작업에서 유용합니다.

swift
let doubled = numbers.map { $0 * 2 }
let evenNumbers = numbers.filter { $0 % 2 == 0 }
let sum = numbers.reduce(0, +)

성능 최적화

배열의 성능을 최적화하기 위해 reserveCapacity 메서드를 사용할 수 있습니다. 이는 배열의 크기를 미리 할당하여 추가 작업 시 성능 저하를 방지합니다.

swift
var dynamicArray: [Int] = []
dynamicArray.reserveCapacity(1000)

비동기 작업과 배열

Swift의 비동기 작업을 처리할 때 배열을 효과적으로 사용할 수 있습니다. 예를 들어, 여러 비동기 작업의 결과를 배열에 저장하고, 이를 처리하는 방법을 살펴봅시다.

swift
func fetchData(completion: @escaping ([String]) -> Void) {
    DispatchQueue.global().async {
        let data = ["Data1", "Data2", "Data3"]
        completion(data)
    }
}

fetchData { data in
    print(data)
}

딕셔너리 (Dictionary)

딕셔너리의 고급 사용법

딕셔너리는 키-값 쌍으로 데이터를 저장하는 컬렉션 타입입니다. 딕셔너리를 더 효율적으로 사용하는 방법을 알아봅시다.

딕셔너리 병합

두 딕셔너리를 병합할 때 merging 메서드를 사용할 수 있습니다. 이는 데이터 소스를 통합하거나, 기본 설정과 사용자 설정을 합칠 때 유용합니다.

swift
let dict1 = ["a": 1, "b": 2]
let dict2 = ["b": 3, "c": 4]
let mergedDict = dict1.merging(dict2) { (current, new) in new }

딕셔너리 필터링

딕셔너리의 특정 조건에 맞는 요소를 필터링 할 수 있습니다. 이는 데이터 클렌징 및 특정 조건에 맞는 데이터 추출에 유용합니다.

swift
let filteredDict = mergedDict.filter { $0.value > 2 }

고차 함수 활용

딕셔너리에서도 mapValues, compactMapValues 등의 고차 함수를 사용하여 값을 변환하거나, nil 값을 제거할 수 있습니다.

swift
let incrementedValues = mergedDict.mapValues { $0 + 1 }
let nonNilValues = mergedDict.compactMapValues { $0 > 2 ? $0 : nil }

성능 최적화

딕셔너리의 성능을 최적화하기 위해 적절한 해시 함수를 사용하는 것이 중요합니다. Swift에서는 커스텀 타입을 딕셔너리의 키로 사용할 때 Hashable 프로토콜을 준수해야 합니다.

swift
struct Person: Hashable {
    let id: Int
    let name: String
}

let peopleDict: [Person: Int] = [Person(id: 1, name: "John"): 90]

세트 (Set)

세트의 고급 사용법

세트는 고유한 값들을 저장하는 컬렉션 타입입니다. 중복된 값을 허용하지 않으며, 효율적인 집합 연산을 지원합니다.

세트 연산

세트는 합집합, 교집합, 차집합 등의 집합 연산을 효율적으로 수행할 수 있습니다.

swift
let setA: Set = [1, 2, 3, 4]
let setB: Set = [3, 4, 5, 6]

let union = setA.union(setB) // [1, 2, 3, 4, 5, 6]
let intersection = setA.intersection(setB) // [3, 4]
let difference = setA.subtracting(setB) // [1, 2]

세트 필터링

세트의 특정 조건에 맞는 요소를 필터링 할 수 있습니다. 이는 데이터의 특정 조건을 만족하는 요소를 쉽게 추출하는 데 유용합니다.

swift
let filteredSet = setA.filter { $0 > 2 } // [3, 4]

성능 최적화

세트의 성능을 최적화하기 위해 적절한 해시 함수를 사용하는 것이 중요합니다. Swift에서는 커스텀 타입을 세트의 요소로 사용할 때 Hashable 프로토콜을 준수해야 합니다.

swift
struct CustomType: Hashable {
    let id: Int
}

let customSet: Set<CustomType> = [CustomType(id: 1), CustomType(id: 2)]

고급 활용 사례

데이터 변환

배열, 딕셔너리, 세트를 상호 변환하는 방법을 알아봅시다. 이 방법은 데이터 변환 및 정리에 매우 유용합니다.

swift
let array = [("a", 1), ("b", 2), ("c", 3)]
let dict = Dictionary(uniqueKeysWithValues: array) // ["a": 1, "b": 2, "c": 3]
let set = Set(array.map { $0.1 }) // [1, 2, 3]

성능 비교

배열, 딕셔너리, 세트는 각기 다른 용도와 성능 특성을 가지고 있습니다. 예를 들어, 배열은 순서가 중요할 때 유용하고, 딕셔너리는 키-값 조회가 빠르며, 세트는 고유한 값 관리에 최적화되어 있습니다. 성능을 고려해 적절한 컬렉션 타입을 선택하는 것이 중요합니다.

비동기 프로그래밍과 컬렉션

Swift에서 비동기 작업을 처리할 때 컬렉션 타입을 효과적으로 사용하는 방법도 중요합니다. 예를 들어, 여러 비동기 작업의 결과를 배열에 저장하거나, 비동기 작업 중간에 딕셔너리를 통해 상태를 관리할 수 있습니다.

swift
func fetchData(completion: @escaping ([String: Int]) -> Void) {
    DispatchQueue.global().async {
        let result = ["key1": 1, "key2": 2]
        completion(result)
    }
}

fetchData { data in
    print(data) // ["key1": 1, "key2": 2]
}

결론

Swift의 배열, 딕셔너리, 세트는 매우 강력한 컬렉션 타입입니다. 고급 개발자는 이러한 컬렉션 타입을 더 효율적으로 사용하기 위해 고급 기능들을 익히고, 성능 최적화 기법을 이해해야 합니다. 이 가이드를 통해 Swift의 컬렉션 타입에 대한 심화 지식을 쌓고, 실무에서 더욱 효율적이고 강력한 코드를 작성할 수 있기를 바랍니다. Swift의 다양한 기능을 활용하여 더욱 높은 수준의 프로그래밍 스킬을 갖추길 바랍니다.