Swift-Language Guide 5.7 / Collection Types (한국어)

newon-seoul·2022년 6월 29일
0

Swift-Language Guide 5.7

목록 보기
3/6
post-thumbnail

초록

Swift 는 3개의 주요 컬렉션 (Collection) 자료형 Array, Set, Dictionaries 을 제공합니다. Array 는 값을 지니는 정렬된 컬렉션이며, SetDictionaries 는 비정렬 컬렉션으로, 각각 고유의 값을 지니거나 Key-Value 로 이루어진 컬렉션입니다.

Swift 에서 각 컬렉션들은 지닐 수 있는 자료형이 명백하게 정의되기에, 사용자는 잘못된 형태의 값을 컬렉션에 넣을 수 없게 됩니다. 또한 각각의 컬렉션은 컬랙션 내에서 동일한 자료형만 반복될 것임을 확신할 수 있게 됩니다.

Mutability of Collections(컬렉션 변경 가능 여부)

Array, Set, Dictionaries 를 만들 때 변수(variable)로 만들게 되면 해당 컬렉션은 변경 및 수정이 가능하게 되며, 이와 반대로 상수(constant)로 만들게되면 초기화를 할 때를 제외하면 변경 및 수정이 불가능하게 됩니다.

Arrays (배열)

array 는 같은 자료형으로 정렬된 목록의 값들을 저장하는 컬렉션입니다.

Note: Swift 의 배열은 Foundation 프레임워크의 NSArray class 와 연결되어 있습니다. Array 를 Foundation 과 Cocoa 를 통해 사용하고 싶다면 Bridging Between Array and NSArray 를 참고해주세요.

Array Type Shorthand Syntax (Array 자료형 줄임 문법)

Swift Array 자료형은 Array<Element> 의 형태로 정의됩니다. 이때 짧게 사용하는 방법으로 [Element] 를 통해 사용할 수 있습니다. 두 형태는 기능적으로 동일하며, 이하 Swift Language Guide 에서는 줄임 표현을 사용할 것 입니다.

Creating an Empty Array

빈 배열은 타음과 같이 만들 수 있습니다.

var someInts: [Int] = []
print("someInts 는 [Int] 자료형으로 \(someInts.count) 개수 만큼 원소를 갖고 있습니다.")
// "someInts 는 [Int] 자료형으로 0 개수 만큼 갖고 원소를 갖고 있습니다."

배열이 variable 에 Int 자료형으로 선언되었으므로 다음과 같이 사용할 수 있습니다.

someInts.append(3)
// someInts 는 이제 Int 자료형의 원소를 1개 갖고 있습니다.
someInts = []
// someInts 는 이제 빈 배열이지만, 여전히 [Int] 형입니다.

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

Swift 의 배열 자료형은 초기화 시 특정 사이즈에 동일한 값을 넣어서 초기화 하는 방법을 제공합니다.

var threeDoubles = Array(repeating: 0.0, count: 3)
//threeDoubles 는 [Double] 자료형에 [0.0, 0.0, 0.0] 입니다.

// 번역 : 이런 형태도 가능합니다.
var threeDoubles = [Double](repeating: 0.0, count: 3)
// threeDoubles 는 [Double] 자료형에 [0.0, 0.0, 0.0] 입니다.

Creating an Array by Adding Two Arrays Together (두 배열을 합쳐 하나의 배열 만들기)

동일한 두 자료형의 배열을 + 연산자를 통해서 두 배열이 합쳐진 새로운 배열을 생성할 수 있습니다.

var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles 는 [Double] 자료형이며, [0.0, 0.0, 0.0, 2.5, 2.5, 2.5,] 입니다.

Creating an Array with an Array Literal(리터럴을 통해 배열 만들기)

리터럴을 통해서도 배열을 만들 수 있습니다. [] 안에 원하는 원소를 넣고, , 로 구분할 수 있습니다.

var shoppingList: [String] = ["Eggs", "Milk"]
// shoppingList 는 [String] 자료형에 Eggs 와 Milk 를 담고 있습니다.

이때 원소를 하나의 자료형으로 통일하면 배열의 자료형은 원소의 자료형으로 자동캐스팅이 됩니다.

var shoppingList = ["Eggs", "Milk"]
// shoppingList 는 [String] 자료형에 Eggs 와 Milk 를 담고 있습니다.

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

배열의 메소드와 프로퍼티, 인덱스 문법을 통해 배열에 접근하거나 수정할 수 있습니다.

배열의 개수는 count 프로퍼티를 사용할 수 있습니다.

print("shoppingList 는 \(shoppingList.count)개의 원소를 갖고 있습니다.")
// 출력 : shoppingList 는 2개의 원소를 갖고 있습니다.

배열이 빈 값인지 확인하고 싶다면 isEmpty 프로퍼티를 사용할 수 있습니다. isEmptycount == 0 과 동일합니다.

if shoppingList.isEmpty{
	print("쇼핑리스트는 비어있습니다.")
} else {
	print("쇼핑 리스트는 비어있지 않습니다.")
}
// 출력 : 쇼핑 리스트는 비어있지 않습니다.

배열에 원소를 추가하고 싶다면 append(_:) 메소드를 사용할 수 있습니다.
* 번역 : 메소드나 함수에서 매개변수 앞에 _ 가 있으면 호출할 때 매개변수 라벨을 생략할 수 있습니다.

shoppingList.append("Flour")
// shoppingList 는 이제 3개의 아이템이 되었고, 팬케이크를 구울 것 같네요 :)

혹은 이런 방법으로도 배열에 원소를 추가할 수 있습니다.

shoppingList += ["Baking Powder"]
// 쇼핑리스트는 이제 4개의 아이템을 갖고 있습니다.
shoppingList += ["Chocolate Spread", "Cheese", "Butter"]
// 쇼핑리스트는 이제 7개의 아이템을 갖고 있습니다.

인덱스 문법을 활용하여 배열 안의 값을 확인하거나, 새로운 값을 할당할 수도 있습니다.

var firstItem = shoppingList[0]
shoppingList[0] = "Six eggs"

// firstItem 은 Eggs 가 되고,
// shoppingList[0] 는 "Six eggs" 가 됩니다.
// 번역 : 이때, 배열은 "값 타입" 이기 때문에, firstItem 이 Six eggs 로 변경되지 않습니다. 

인덱스 문법을 활용할때는 사용하고자 하는 인덱스가 배열의 범위안에 있는지 확인하여야 합니다. 만약 배열에 포함되어 있지 않은 인덱스를 사용하면 런타임 에러가 발생할 것 입니다.

한편 다음과 같이 인덱스 문법을 활용하여 특정 범위의 배열에 접근하거나 수정할 수도 있습니다. 이때 배열은 배열 리터럴의 크기로 조정하여 기존의 값에 합쳐지게 됩니다.

shoppingList[4..6] = ["Bananas", "Apples"]
// shoppingList 는 이제 기존 3개 원소를 2개 원소로 줄여, 
// 6개의 아이템을 갖게 됩니다.

배열 내 특정 인덱스에 삽입을 하고 싶다면 insert(_:at:) 메소드 를 사용할 수 있습니다.

shoppingList.insert("Maple Syrup", at 0)
// shoppingList 의 첫번째 원소에 Maple Syrup 이 들어가며 , 총 7개의 원소를 갖게 됩니다.

이와 유사하게 배열 내 특정 인덱스를 삭제하고 싶다면 remove(at:) 메소드를 사용할 수 있습니다. remove 메소드는 삭제한 원소를 리턴하는데, 필요없다면 무시하고 사용할 수 있습니다.

let mapleSyrup = shoppingList.remove(at: 0)

Note : 배열의 총 크기는 0 ~ count - 1 입니다. 이때 count 가 0 이라면 빈 배열로, 접근할 수 없습니다. 인덱스를 활용한다면 이 점에 유의해서 사용해주세요.

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

배열 내 전체 값들을 for-in 반복문을 통해 접근할 수 있습니다.

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

반복 시 인덱스가 필요하다면 다음과 같은 형태도 고려해볼 수 있습니다.

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 (세트 )

세트는 비정렬 컬렉션에 같은 자료형의 값들을 고유 하게 저장하는 컬렉션을 의미합니다. 원소들의 순서가 중요하지 않거나, 원소가 반드시 1개만 존재해야 한다면 set 를 사용할 수 있습니다.

Note : Swift 의 set 자료형은 Foundation 의 NSSet class 를 따릅니다. 더 자세한 내용은 Bridging Between Set and NSSet 를 확인해주세요.

Hash Values for Set Types (Set 자료형을 위한 해쉬 값)

Set 에 저장되는 값들은 반드시 hashable, 즉 각 값들이 hash value 를 지녀 다른 값과 계산할 수 있는 자료형이어야 합니다. hash value 는 Int 값이며, 동일한 값은 동일한 hash value 를 갖고 있어야합니다.

번역 : Swift 4.2 이후로부터 hashable 이 적용된 자료형은 컴파일러에서 자체적으로 hash algorithm 이 적용됩니다. 이에 따라 보다 빠른 최적화가 필요하거나 쌉컴덕 이 아니라면 컴파일러에게 맡기고, 아무것도 안하면 됩니다 ! sturct 등은 해당 제네릭 자료형에 Hashable protocol, equatable protocl 을 적용하면 됩니다. 참고

Swift 내 기본 자료형들 (String, Int, Double, Bool 등) 은 자체적으로 hashable 를 내장하고 있으며 set valuedictionary key type 에 사용할 수 있습니다. Enumeration 값 역시 자체적으로 hashable 이 적용됩니다.

Set Type Synatx (set 자료형 문법)

Set 은 Set<Element> 로 정의할 수 있으며, 배열과 달리 짧은 문법은 없습니다.

Creating and Initializing an Empty Set (빈 set 만들기)

var letters = Set<Character>()
print(letters 는 Set<Character> 자료형으로, \(letters.count)개의 원소를 갖고 있습니다.)
// letters 는 Set<Character> 자료형으로 0개의 원소를 갖고 있습니다.

한번 Set 을 초기화하면 자료형이 정해지기에 자료형을 언급하지 않아도 됩니다. 다음과 같이 활용할 수 있습니다.

letters.insert("a")
letters = []

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

리터럴을 통해 Set 을 초기화할 수도 있습니다.

var favoriteGeners: Set<String> = ["Rock", "Classical", "Hip hop"]
// favoriteGeners 는 3개의 원소로 초기화되었습니다.

// 다음과 같이 짧게 표현할 수도 있습니다.
var favoriteGeners: Set = ["Rock", "Classical", "Hip hop"]

한번 선언되면, 해당 Set 는 같은 자료형만 삽입할 수 있게 됩니다.

Accessing and Modifying a Set (Set 에 접근과 수정하기)

다음 메소드와 프로퍼티를 통해 Set 에 접근하거나 수정할 수 있습니다.

세트의 개수는 count 프로퍼티를 사용할 수 있습니다.

print("저는 \(favoriteGenres.count)개의 음악 장르를 선호해요.")
// 출력 : 저는 3개의 음악 장르를 선호해요.

세트가 빈 값인지 확인하고 싶다면 isEmpty 프로퍼티를 사용할 수 있습니다. isEmptycount == 0 과 동일합니다.

if favoriteGenres.isEmpty {
    print("음악이 있기만 한다면, 난 까탈쟁이는 아니에요.")
} else {
    print("전 특정 음악을 선호해요.")
}
// 출력: "전 특정 음악을 선호해요. "

세트에 원소를 삽입하고 싶다면 insert(_:at:) 메소드 를 사용할 수 있습니다.

favoriteGenres.insert("Jazz")
// favoriteGenres 는 이제 4개의 원소를 갖고 있습니다.

이와 유사하게 세트 내 특정 인덱스를 삭제하고 싶다면 remove(at:) 메소드를 사용할 수 있습니다. remove 메소드는 삭제한 원소를 리턴하는데, 필요없다면 무시하고 사용할 수 있습니다.

if let removeGenre = fvoriteGenres.remove("Rock") {
	print("\(removeGenre)? 없앱니다 ~ ")
} els e{
	print("그런 장르 좋아한 적 없습니다.")
}
// 출력 : "Rock"? 없앱니다 ~

너는 록을 좋아하지 않아

Note : 배열의 총 크기는 0 ~ count - 1 입니다. 이때 count 가 0 이라면 빈 배열로, 접근할 수 없습니다. 인덱스를 활용한다면 이 점에 유의해서 사용해주세요.

한편 Set 가 특정 원소를 포함하고 있는지 확인하고 싶다면 contains(_:) 메소드를 사용할 수 있습니다.

if favoriteGenres.contains("Funk") {
	print("하하 내 화려한 발재간을 보아라")
} else {
	print("너무 시끄럽네 ..")
}
// 출력 : 너무 시끄럽네 ..

Iterating Over a Set (Set 반복하기)

세트 내 전체 값들을 for-in 반복문을 통해 접근할 수 있습니다.

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

Swift 의 set 은 특정한 정렬이 없습니다. 혹시 특정한 기준으로 정렬된 set 를 반복하고 싶다면 sorted() 메소드를 활용해보세요.

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

Performing Set Operations (Set 최적화 수행)

Set 자료형은 set 의 구조를 작업하는 효율적인 메소드들을 제공합니다. 합집합, 교집합, 차집합, 대칭차집합 와 같은 내용입니다.

Fundamental Set Operations (기본적인 Set 작업)

다음과 같은 작업을 수행할 수 있습니다.

  • intersection(_:) 메소드를 활용하여 교집합 set 을 얻을 수 있습니다.
  • symmetricDifference(_:) 메소드를 활용하여 대칭차집합 set 을 얻을 수 있습니다.
  • union(_:) 메소드를 활용하여 두 set 을 합칠 수 있습니다.
  • subtracting(_:) 메소드를 활용하여 여집합 set 을 얻을 수 있습니다.

코드로 표현하면 다음과 같습니다.

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 (Set 의 소속과 동일성)

다음 도표를 통해 Set 의 관계를 살펴볼 수 있습니다. Set a 는 Set b 를 포함하므로 a 는 b 의 상위집합입니다. 한편 b 는 a 의 부분집합이 됩니다. Set c 는 b 와 관련이 없는 별개의 집합이 됩니다.

  • == 연산자를 통해 두 Set 이 모두 동일한 원소들을 포함하는지 확인할 수 있습니다.
  • isSubset(of:) 메소드를 통해 어떤 Set 이 다른 Set 의 부분집합인지 확인할 수 있습니다.
  • isSuperset(of:) 메소드를 통해 어떤 Set 이 다른 Set 의 상위집합인지 확인할 수 있습니다.
  • isStrictSubset(of:) 혹은 isStrictSuperset(of:) 메소드들을 통해 각각이 부분집합, 상위집합이되 동일한 집합이 아닌지 확인할 수 있습니다.
  • isDisjoint(with:) 을 통해 두 Set 가 공통된 원소를 없는지 확인할 수 있습니다.

코드로 표현하면 다음과 같습니다.

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 는 키와 값이라는 한 쌍을 기준으로 같은 자료형을 저장하는 비정렬 컬렉션입니다. 각 값들은 고유한 키에 속하게 되며, 이를 통해 딕셔너리 내에 값들을 확인할 수 있게 됩니다. 비정렬 컬렉션이므로, 실제 사전과 같이 특정 값을 찾고 싶다면 키를 통해 확인할 수 있습니다.

Note: Swift 의 딕셔너리는 Foundation 의 NSDictionary class 를 따릅니다. 자세한 사항은 Bridging Between Dictionary and NSDictionary 에서 확인할 수 있습니다.

Dictionary Ype Shorthand Syntax (딕셔너리 자료형 줄임 표현)

딕셔너리는 Dictionary<Key, Value> 의 형태로 선언되지만, [Key:Value] 로 짧게 표현할 수도 있습니다. 이때 Key 값은 Hashable protocol 을 따르는 자료형이어야 합니다.

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

var namesOfIntegers: [Int: String] = [:]
// namesOfIntegers 는 빈 [Int:String] 딕셔너리 입니다.

한번 딕셔너리를 초기화하면 자료형이 정해지기에 자료형을 언급하지 않아도 됩니다. 다음과 같이 활용할 수 있습니다.

namesOfIntegers[16] = "sixteen"
// namesOfIntegers 는 이제 1 쌍의 Key-Value 를 갖고 있습니다.
namesOfIntegers = [:]
// naemsOfIntegers 는 빈 딕셔너리입니다.

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

리터럴을 통해 딕셔너리를 초기화할 수도 있습니다.

var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// airports 는 2개의 키-쌍 값을 갖고 있습니다.

// 다음과 같이 짧게 표현할 수도 있습니다.
var airports = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]

한번 선언되면, 해당 딕셔너리는 같은 자료형만 삽입할 수 있게 됩니다.

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

다음 메소드와 프로퍼티를 통해 딕셔너리에 접근하거나 수정할 수 있습니다.

딕셔너리의 개수는 count 프로퍼티를 사용할 수 있습니다.

print("공항 딕셔너리는 \(airports.count)개의 원소를 갖고 있습니다.")
// 출력: "공항 딕셔너리는 2개의 원소를 갖고 있습니다."

딕셔너리가 빈 값인지 확인하고 싶다면 isEmpty 프로퍼티를 사용할 수 있습니다. isEmptycount == 0 과 동일합니다.

if airports.isEmpty {
    print("공항 노선이 없습니다.")
} else {
    print("공항 노선이 있습니다.")
}
// Prints "공항 노선이 없습니다."

딕셔너리에 원소를 삽입하고 싶다면 인덱스 문법을 사용할 수 있습니다.

airports["LHR"] = "London"
// 공항 딕셔너리는 이제 3개의 원소를 갖고 있습니다.

딕셔너리의 원소를 수정하고 싶을때도 인덱스 문법을 사용할 수 있습니다.

airports["LHR"] = "London Heathrow"
// "LHR" 의 값은 "London Heathrow" 로 변경되었습니다.

인덱스 문법 대신 updateValue(_:forKey:) 메소드를 통해 특정 키의 값을 수정할 수 있습니다. 이때 updateValue(_:forKey:) 메소드는 해당 키가 존재하지 않는다면 nil 을 존재한다면 이전의 value 를 리턴합니다.

if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
    print("DUB 키의 이전 값은 \(oldValue) 입니다.")
}
// 출력: "DUB 키의 이전 값은 Dublin 입니다."

인덱스 문법 역시 이와 유사한 표현을 사용할 수 있습니다. 단, updateValue(_:forKey:) 메소드와 달리 이전의 값이 있더라도 그 값을 리턴하지 않습니다.

if let airportName = airports["DUB"] {
    print("공항 이름은 \(airportName) 입니다.")
} else {
    print("해당 공항은 없습니다.")
}
// Prints "공항 이름은 Dublin Airport 입니다."

딕셔너리 내 특정 키를 삭제하고 싶다면 인덱스 문법을 활용하여 특정 키에 nil 을 할당하면 됩니다.

airports["APL"] = "Apple International"
// "Apple International" 는 실제 공항이 아니므로 삭제합니다.
airports["APL"] = nil
// APL 은 딕셔너리에서 삭제되었습니다.

이와 유사하게 remove(at:) 메소드를 사용할 수 있습니다. remove 메소드는 삭제한 원소를 리턴하는데, 필요없다면 무시하고 사용할 수 있습니다.

if let removedValue = airports.removeValue(forKey: "DUB") {
    print("삭제된 공항의 이름은 \(removedValue) 입니다.")
} else {
    print("공항 딕셔너리는 DUB 키에 값을 갖고 있지 않습니다.")
}
// 출력: "삭제된 공항의 이름은 \(removedValue) 입니다."

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

딕셔너리 내 전체 값들을 for-in 반복문을 통해 접근할 수 있습니다.

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

딕셔너리의 키나 벨류로 반복하고 싶다면 다음과 같이 사용할 수 있습니다.

for airportCode in airports.keys {
    print("공항 코드: \(airportCode)")
}
// 공항 코드: LHR
// 공항 코드: YYZ

for airportName in airports.values {
    print("공항 이름: \(airportName)")
}
// 공항 이름: London Heathrow
// 공항 이름: Toronto Pearson

혹시 API 에 사용하기 위해 딕셔너리의 키나 벨류가 필요하다면 Array instance 를 활용할 수 있습니다.

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

let airportNames = [String](airports.values)
// airportNames 는 ["London Heathrow", "Toronto Pearson"]
profile
나만 고양이 없어

0개의 댓글