[Swift 공식문서 읽기]Collection Types

llim🧚🏻‍♀️·2021년 8월 10일
1

Swift

목록 보기
4/26
post-thumbnail

안녕하세요. 엘림입니다🙇🏻‍♀️

Swift 공식 문서 정독하기 4편입니다!

제 스타일대로 정리했으니 추가적으로 더 필요한 정보는
공식문서 링크를 눌러 확인해주세용!

사실 거의 한국어로 번역된 사이트를 확인했습니다!ㅎㅎ

자, 그럼 시작해볼까요

이 글은 공부하면서 작성한 글이기 때문에 잘못된 정보가 있을 수 있습니다.🥺
금방 잊어버릴... 미래의 저에게 다시 알려주기 위한 글이다보니
혹시라도 틀린 부분이 있다면, 댓글로 친절하게 알려주시길 부탁드립니다.🙏


컬렉션 타입

Swift에서는 기본 콜렉션 타입으로 Array, Set, Dictionary를 지원합니다.
배열은 정렬된 값 모음, 집합은 고유한 값의 정렬되지 않은 컬렉션, 딕셔너리는 키-값으로 된 정렬되지 않은 컬렉션입니다.
이 컬렉션들은 키와 값의 타입이 명확하기 때문에, 실수로 잘못된 유형의 컬렉션에 삽입할 수 없습니다.
또한 변수로 선언하면 변경이 가능하고, 상수로 선언하면 변경이 불가능합니다.

배열

배열은 순서가 있으며, 같은 종류의 타입이 저장됩니다. 또한 같은 값이 배열의 다른 위치에서 여러번 나타날 수 있씁니다.
배열은 Array<Element>[Element]로 작성될 수 있습니다.

배열 생성

var someInts = [Int]()
print("someInts is of type [Int] with \(someInts.count) items.")
// someInts is of type [Int] with 0 items.
someInts.append(3)
// 배열에 3을 추가 했습니다.
someInts = []
// 배열을 비웠습니다. 배열의 아이템 타입은 그대로 Int로 유지됩니다.

var threeDoubles = Array(repeating: 0.0, count: 3)
// threeDoubles : Double 타입의 [0.0, 0.0, 0.0]

var anotherThreeDoubles = Array(repeating: 2.5, count: 3)
// anotherThreeDoubles : [2.5, 2.5, 2.5]

var sixDoubles = threeDoubles + anotherThreeDoubles
// sixDoubles : [0.0, 0.0, 0.0, 2.5, 2.5, 2.5]

var shoppingList: [String] = ["Eggs", "Milk"]
var shoppingList = ["Eggs", "Milk"] // 타입 추론 사용 가능

접근 및 수정

배열의 원소 개수 확인

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

배열이 비었는지 확인

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

배열에 원소 추가

shoppingList.append("Four")
// shoppingList.count = 3

+=를 통해서도 배열에 원소를 추가할 수 있음

shoppingList += ["Baking Powder"]
// shoppingList.count = 4
shoppingList += [Chocolate Spread", "Cheese", "Butter"]
// shoppingList.count = 7

배열의 특정 위치의 원소 접근

var firstItem = shoppingList[0]
// firstItem : "Eggs"

인덱스를 사용하여 원소를 변경할 수 있음

shoppingList[4..6] = ["Bananas", "Apples"]
// 4, 5, 6번째 인덱스 아이템을 Banana, Apples로 변환
// 즉, 아이템 3개가 2개로 줄었다.

특정 위치에 원소 추가/삭제/접근

shoppingList.insert("Maple Syrup", at:0)
let mapleSyrup = shoppingList.remove(at: 0)
firstItem = shoppingList[0]
// firstItem : "Six eggs"
let apples = shoppingList.removeLast()

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

Set

순서 없이 동일한 타입의 값을 저장하며, 중복된 값이 없어야 하는 경우 배열 대신 사용합니다.
Set 형태로 저장되기 위해서는 반드시 타입이 hashable이어야만 합니다. Swift에서 String, Int, Double, Bool 같은 기본 타입과 연결된 값이 없는 enum은 기본적으로 hashable입니다. 사용자 정의 타입도 Hashable 프로토콜을 준수하면, 사용할 수 있습니다.
(해시 값은 동일하게 비교되는 모든 객체에 대해 동일한 Int 값을 가집니다. 따라서 a == b라면, a와 b의 해시 값은 같습니다.)

생성

var letters = Set<Character>()
print("letters is of type Set<Character> with \(letters.count) items.")
// letters is of type Set<Character> with 0 items.
letters.insert("a")
letters = [] // 타입이 이미 지정되어 있어서 사용 가능

var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
var favoriteGenres: Set = ["Rock", "Classical", "Hip hop"]
// 들어올 값이 스트링이라는 것을 알아서 타입 추론이 가능함

접근 및 수정

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

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

favoriteGenres.insert("Jazz")

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

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

for-in

for genre in favoriteGenres {
    print("\(genre)")
}
// Classical
// Hip hop
// Jazz
/// 셋은 순서가 없어서 매번 다르게 나옵니당!

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

Set 명령어

  • 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]

  • "같음" 연산자(==)는 두 집합이 완전히 같은지
  • isSubset(of:)는 현재 집합의 모든 값이 지정된 집합에 포함되어 있는지
  • isSuperset(of:)는 지정된 집합의 모든 값이 현재 집합에 포함되어 있는지(isSubset와 반대(?)로 생각하면 되는 듯)
  • isStrictSubset(of:)또는 isStrictSuperset(of:)는 집합이 하위 집합인지 상위 집합인지(지정된 집합과 같지 않음)
  • isDisjoint(with:)는 두 집합에 공통된 값이 없는지
let houseAnimals: Set = ["🐶", "🐱"]
let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"]
let cityAnimals: Set = ["🐦", "🐭"]

farmAnimals == houseAnimals
// 거짓
houseAnimals.isSubset(of: farmAnimals)
// 참
farmAnimals.isSuperset(of: houseAnimals)
// 참
houseAnimals.isStrictSubset(of: farmAnimals)
// 참
houseAnimals.isStrictSuperset(of: farmAnimals)
// 거짓
farmAnimals.isStrictSuperset(of: houseAnimals)
// 참
farmAnimals.isDisjoint(with: cityAnimals)
// 참

Dictionary

순서 없이 같은 타입의 키들과 같은 타입의 값들을 쌍으로 저장합니다.
각 값은 딕셔너리 내에서 해당 값의 식별자 역할을 하는 고유 키와 연결됩니다.
특정 단어에 대한 값을 찾는 것이 실제 사전을 이용하는 것과 비슷합니다.
보통 주어진 식별자를 기반으로 값을 조회해야할때 사용합니다.
(키는 Hashable 프로토콜을 준수해야합니다.)

생성

var namesOfIntegers = [Int: String]()
namesOfIntegers[16] = "sixteen"
namesOfIntegers = [:]
// 빈 사전

var airports: [String: String] = = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// [key 1: value 1, key 2: value 2, key 3: value 3] 형태로 사전을 선언할 수 있습니다.

접근 및 변경

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

if airports.isEmpty {
    print("The airports dictionary is empty.")
} else {
    print("The airports dictionary is not empty.")
}
// 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"


if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
    print("The old value for DUB was \(oldValue).")
}
// "The old value for DUB was Dublin." 업데이트 이전 값 출력됨

if let airportName = airports["DUB"] {
    print("The name of the airport is \(airportName).")
} else {
    print("That airport isn't in the airports dictionary.")
}
// "The name of the airport is Dublin Airport." 방금 전에 저장한 값 저장된 것 확인

if let oldValue = airports.updateValue("Incheon Airport", forKey: "KOR") {
    print("The old value for KOR was \(oldValue).")
} else {
    print("That airport isn't in the airports dictionary.")
}
// "That airport isn't in the airports dictionary." 값은 업데이트하면서 저장 되었지만, 당시에는 값이 없었으므로 else 출력

삭제

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

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

for-in

for (airportCode, airportName) in airports {
    print("\(airportCode): \(airportName)")
}

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

for airportName in airports.values {
    print("Airport name: \(airportName)")
}

copy-on-write

배열, 딕셔너리 및 문자열과 같은 표준 라이브러리에 의해 정의된 컬렉션은 복사의 성능 비용을 줄이기 위해 최적화를 사용합니다. 즉시 복사본을 만드는 대신 이러한 컬렉션은 원본 인스턴스와 복사본 간에 요소가 저장되는 메모리를 공유합니다. 컬렉션 복사본 중 하나가 수정되면 수정 직전에 요소가 복사됩니다. 코드에서 볼 수 있는 동작은 항상 복사가 즉시 발생한 것처럼 보이지만, 실제로는 copy on write 때문에 수정되기 전에는 복사되지 않습니다.


오늘은 스위프트 공식문서에서 Collection Types를 읽어보았습니다~
다음에는 Control Flow를 읽어보도록 하겠습니다!

감사합니다🙇🏻‍♀️

profile
한달 차 iOS 개발자입니다🐥

0개의 댓글