Swift 콜렉션 타입(Collection Types)

이재원·5일 전
0

Swift

목록 보기
4/4

콜렉션 타입(Collection Types)

Swift는 콜렉션의 값을 저장하기 위한 배열(array), 집합(set), 딕셔너리(dictionary)와 같은 3개의 원시적인 콜렉션 타입을 제공합니다.
배열은 콜렉션 값레 순서를 가지고 있습니다. 집합은 반복되지 않는 값에 순서가 없는 콜렉션 타입입니다. 딕셔너리는 키-값 쌍의 순서가 없는 콜렉션 타입입니다.

!https://velog.velcdn.com/images/jwlee010523/post/b68e6921-190d-4ac5-b09d-4c325f3d1975/image.png

Note
Swift의 배열, 집합, 그리고 딕셔너리 타입은 제너릭 콜렉션으로 구현됩니다.

콜렉션의 가변성(Mutablility of Collections)

배열, 집합, 또는 딕셔너리를 생성하고 변수에 할당하면 생성된 콜렉션은 변경 가능하다. 이것은 콜렉션이 생성된 후에 콜렉션의 아이템을 추가, 삭제, 또는 변경할 수 있다는 뜻입니다. 배열, 집합, 또는 딕셔너리를 상수에 할당하면 이 콜렉션은 불가변성이며 크기와 콘텐츠를 변경할 수 없습니다.

배열(Array)

기본값 배열 생성(Creating an Array with a Default Value)

Swift 타입은 같은 기본 값으로 설정하고 크기를 고정하여 배열을 생성하는 초기화도 제공합니다. 적합한 타입의 기본값과 새로운 배열에 반복될 값의 횟수를 초기화에 전달합니다.

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

배열을 더해 생성하기

같은 타입의 배열을 덧셈 연산자를 통해 새로운 배열을 생성할 수 있습니다.

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]

배열 접근과 수정(Accessing and Modifying an Array)

배열에 아이템 갯수를 알려면 읽기 전용 count 프로퍼티로 확인하면 됩니다.

var shoppingList = ["Eggs", "Milk"]
print("The shopping list contains \(shoppingList.count) items.")
// Prints "The shopping list contains 2 items."

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

또한 하나 이상의 동등한 아이템의 배열은 덧셈 대입 연산자(+=)를 통해 추가할 수 있습니다.

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

변경할 값들이 변경할 범위와 다른 길이를 가지고 있더라도 서브 스크립트 구문으로 범위 안에 값을 한번에 변경할 수 있습니다.

shoppingList[4...6] = ["Bananas", "Apples"]
// "Chocolate Spread", "Cheese" -> "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

위 코드는 shoppingList 배열의 0번째 인덱스에 Maple Syrup의 값을 가진 새로운 아이템을 추가합니다.

비슷하게 remove(at:) a메서드를 통해 배열의 아이템을 삭제할 수 있습니다. 이 메서드는 해당 인덱스의 아이템을 삭제한 아이템을 반환합니다.(필요 없을시 무시해도 됨)

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

Note
배열의 범위를 넘는 인덱스에 접근하거나 수정하게 되면 런타임 에러가 발생합니다. 따라서 count 프로퍼티를 사용하여 안전하게 접근할 필요가 있습니다.

배열의 마지막 아이템을 삭제하고 싶다면 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() 메서드를 사용합니다. 배열의 각 아이템에 대해 정수와 아이템을 조합하여 튜플로 반환합니다.

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

집합(Sets)

집합은 콜렉션에 순서와 상관없이 같은 타입의 다른 값을 저장합니다. 아이템의 순서가 중요하지 않거나 아이템이 반복되면 안될 때 배열 대신 집합을 사용할 수 있습니다.

Note
Swift의 집합 타입은 Foundation의 NSSet 클래스와 연결됩니다.

집합 타입을 위한 해쉬 값(Hash Values for Set Types)

집합에 저장하기 위해 타입은 반드시 hashable이어야 합니다. 즉, 해쉬 값(hash value)을 계산할 수 있는 방법을 타입은 제공해야 합니다. 해쉬 값은 동일하게 비교되는 모든 객체데 대해 동일한 Int 값으로 a==b이면 a.hashValue == b.hashValue를 따릅니다.

Swift의 모든 기본 타입(String, Int, Double, Bool)은 기본적으로 hashable이고 집합의 값 타입 또는 딕셔너리의 키 타입으로 사용할 수 있습니다. 연관된 값이 없는 열거형(Enumeration)케이스 값은 기본적으로 hashable입니다.

Note
집합 값 타입 또는 딕셔너리 키 타입으로 사용자화 타입을 사용하려면 Swift 표준 라이브러리의 Hashable 프로토콜을 준수해야 사용 가능합니다.

빈 집합 생성과 초기화(Creating Initializing an Empty 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.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)

집합 콜렉션으로 하나 이상의 값으로 짧은 방법과 같이 배열 리터럴을 사용하여 집합을 초기화 할 수도 있습니다.

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

또는 이렇게 작성할 수 있습니다.

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

이 경우에는 Swift가 String 타입의 집합임을 추론합니다.

집합 접근과 수정(Accessing and Modifying a Set)

메서드와 프로퍼티로 집합에 접근과 수정할 수 있습니다.

count 메서드는 배열에서 사용된 것과 같이 아이템 갯수를 반환합니다.

isEmpty 메서드 역시 배열에서처럼 빈 집합인지 확인 할 수 있습니다.

집합의 insert(_:) 메서드는 배열과 달리 index를 지정하지 않아도 추가 가능합니다.

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

집합의 remove(_:) 메서드를 호출하여 집합의 아이템을 삭제할 수 있습니다. 이 메서드는 집합에 아이템이 있을 경우 삭제하고, 삭제된 값을 반환하거나 해당 아이템이 없을 경우 nil을 반환합니다. 또한 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."

contain(_:) 메서드를 사용하여 집합에 특정 아이템이 포함되어 있는지 알 수 있습니다.

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."

집합 반복(Iteraing Over a Set)

for-in 루프와 함께 집합에 값을 반복할 수 있습니다.

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

집합은 정의된 순서를 가지고 있지 않습니다. 특정 순서로 집합의 값을 반복하려면 집합의 요소를 < 연산자를 사용하여 정렬하여 반환하는 sorted() 메서드를 사용합니다.

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

집합 연산 수행(Performing Set Operations)

기본 집합 연산(Fundamental Set Operations)

스크린샷 2024-05-04 오후 8.25.46.png

  • intersection(_:) : 두 집합의 공통 값을 가지는 새로운 집합을 생성
  • symmetricDifference(_:) : 두 집합의 공통 값을 제외한 새로운 집합 생성
  • union(_:) : 두 집합의 모든 값으로 새로운 집합 생성
  • subtracting(_:) : 메서드를 사용하면 특정 집합의 공통 값을 제외한 새로운 집합 생성
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)

아래 그림은 세 집합 a, b, c를 나타내며 집합의 공통 요소는 겹쳐서 표현하고 있습니다. a는 b의 모든 요소를 포함하므로 집합 a는 b의 초집합(superset)이라 합니다. 반대로 b의 모든 요소가 a에 포함되어 있으므로 집합 b는 집합 a의 부분집합(subset)이라 합니다. 집합 b와 집합 c는 공통 요소가 없으므로 불리집합(disjoint)이라 합니다.

스크린샷 2024-05-04 오후 8.30.22.png

  • 동등 연산자( == )를 사용하여 두 집합의 값이 같은지 확인 가능
  • isSubset(of:) : 집합이 특정 집합에 모든 값이 포함되어 있는지 판단
  • isSuperset(of:) : 집합에 특정 집합의 모든 값을 포함 하는지 판단
  • isStrictSubset(of:) 또는 isStrictSuperset(of:) : 집합이 특정 집합과 같지 않고 부분집합인지 초집합인지 판단
  • isDisJoint(with: ) : 두 집합이 공통 값이 없는지 판단
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)

Switft의 딕셔너리 타입은 Foundation의 NSDictionary 클래스와 연결됩니다.

딕셔너리 타입 짧은 구문 (Dictionary Type Shorthand Syntax)

Swift 딕셔너리의 타입은 Dictionary<Key, Value> 로 적으며 [Key: Value] 와 같은 짧은 형식으로도 나타낼 수 있습니다. 딕셔너리 Key 타입은 집합의 값 타입과 같이 반드시 Hashable 프로토콜을 준수해야 합니다. key는 딕셔너리 키로 사용되는 값의 타입이고 Value는 딕셔너리에 저장될 값의 타입입니다.

빈 딕셔너리 생성(Creating an Empty Dictionary)

var namesOfIntegers = [Int: String]()
// namesOfIntegers is an empty [Int: String] dictionary
// Key is Int type and Value is String type

컨텍스트가 이미 타입 정보를 제공한다면 [ : ]와 같이 작성하여 빈 딕셔너리 리터럴로 빈 딕셔너리를 생성할 수 있습니다.

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

딕셔너리 리터럴로 딕셔너리 생성 (Creating a Dictionary with a Dictionary Literal)

딕셔너리는 아래와 같이 리터럴로 초기화 할 수 있습니다.

[<#key 1#>: <#value 1#>, <#key 2#>: <#value 2#>, <#key 3#>: <#value 3#>]

딕셔너리 리터럴에서 각 키-값 쌍의 키와 같은 콜론으로 구분됩니다. 키-값 쌍은 콤마로 구분하고 대괄호로 둘러싸 리스트 형식으로 작성합니다.

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

딕셔너리 접근과 수정 (Accessing and Modifying a Dictionary)

메서드와 프로퍼티 또는 서브 스크립트 구분을 사용하여 딕셔너리에 접근과 수정이 가능합니다.

배열과 마찬가지로 읽기 전용 count 프로퍼티로 Dictionary 에 아이템의 갯수를 확인할 수 있습니다.

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

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:) 메서드를 사용하여 특정 키에 값을 설정하거나 업데이트 할 수 있습니다.

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."

위의 서브 스크립트 예제와 같이 이 메서드는 해당 키에 값이 존재하지 않으면 값을 설정 하거나 해당 키에 값이 존재하면 값을 업데이트 합니다. 그러나 서브 스크립트와 다르게 updateValue(_ :forKey:) 메서드는 업데이트 수행 후에 이전 값을 반환합니다. 이를 통해 업데이트가 발생했는지 알 수 있습니다.

updateValue(_ :forKey:) 메서드는 딕셔너리의 값 타입의 옵셔널 값을 반환합니다. 예를 들어 딕셔너리에 String 값을 저장하면 String? 타입 또는 “옵셔널 String”을 메서드는 반환합니다. 이 옵셔널 값은 해당 키에 존재한 업데이트 전의 값 또는 존재한 값이 없었을 때는 nil을 포함합니다.

특정 키로 딕셔너리에 접근

특정 키로 딕셔너리에 값을 가져올 때 서브 스크립트 구문을 사용할 수도 있습니다. 값이 없는 키로 요청이 가능하기 때문에 딕셔너리의 서브 스크립트는 딕셔너리의 값 타입의 옵셔널 값을 반환합니다. 딕셔너리에 요청된 키의 값이 있는 경우 서브 스크립트는 그 값의 옵셔널 값을 반환합니다. 반대로는 서브 스크립트는 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) 튜플로 반환되고 튜플의 멤버를 임시 상수 또는 변수로 분리할 수 있습니다.

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

딕셔너리의 keysvalues 프로퍼티로 딕셔너리의 키 또는 값에 반복 가능한 콜렉션을 가져올 수도 있습니다.

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

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

딕셔너리의 키 또는 값을 Array 인스턴스의 API를 사용해야 할 경우 Keys 또는 Values 프로퍼티로 새로운 배열을 초기화 하면 됩니다.

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

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

딕셔너리는 순서를 가지고 있지 않기 때문에 특정 순서로 딕셔너리의 키 또는 값을 반복하려면 keys 또는 values 프로퍼티에 sorted() 메서드를 사용하면 됩니다.

출처
이 글은 swift 공식 문서를 읽고 정리한 내용입니다.
https://bbiguduk.gitbook.io/swift/language-guide-1/collection-types

profile
20학번 새내기^^(였음..)

0개의 댓글