-
Collections Types - Setswift 2021. 4. 8. 00:30
swift의 collection type 중 하나인 Set에 대해서 알아봅시다! (오늘부터 존댓말하기로 함^^)
우선 swift programming guide 부터 시작해보겠습니다.
Set은 동일한 유형의 고유하고, 순서가 정의되지 않는 타입을 저장합니다.
array에 담으려는 자료가 고유하다 즉, 중복 없이 나타나고 순서를 보장하지 않아도 된다면 set을 써도 무방합니다.
참고로 swift의 Set 타입은 NSSet class와 O(1) 시간에 연결(bridgeing)이 가능하다고 하는데요 그러니까 as 연산자를 이용해서 타입캐스팅이 가능하다?? 라는 말 같아요.
이 부분은 나중에 ,, 알아보도록 하겠슴다 ㅎ
Set에 저장하기 위한 자료는 반드시 hashable해야 합니다. 따라서 각 타입은 스스로의 해시 값을 정의할 수 있어야 합니다.
만약 a == b 라는 결과를 나타내는 두 값이 있으면 두 값의 해시 값은 같다고 할 수 있습니다.
swift의 기본 자료형(string, int, bool 등)은 모두 hashable한 값이니 Set에 저장할 수 있습니다.
연관 값이 없는 Enum(이 부분은 추후에 글을 써볼게용) case 값의 경우에도 hashable 합니다.
만약 내가 만든 custom type을 set에 저장하고 싶다면 해당 type이 hashable할 수 있도록 조치를 취해주시면 됩니다!
가장 간단한(?) 방법으로는 해당 타입이 hashable 프로토콜을 채택하는 방법이 있겠죠?!
Set 자료형 생성하기
자 그럼 이제 Set 자료형을 만들어 볼게요.
var charSet = Set<Character>() var intSet = Set<Int>()
다음과 같이 Set<자료형>() 과 같은 형태로 Set 자료형을 만듭니다.
var charSet: Set<Character> = []
해당 Set이 어떤 자료형을 저장하는지 명시해 준다면 위와 같이 빈 Set을 만들 수도 있습니다.
var intSet: Set<Int> = [1, 2, 3] var strSet: Set = ["hi", "i'm", "string", "set"]
또한 마치 array를 초기화 할 때처럼 생성해 줄 수도 있습니다.
swift의 추론을 이용해서 위의 strSet처럼 자료형을 쓰지 않을 수도 있네요.
단, 이 때 저장하는 자료형은 모두 같은 자료형이어야 한다는점 주의!
let strArray = ["안", "녕", "하", "세", "요"] var arraySet = Set(array)
어떠한 배열을 만들고 그 배열을 Set으로 사용하고 싶을 때는 Set(배열)의 형태로도 선언해 줄 수 있어용.
Set 조작하고 확인하기
조작하고 확인한다는 말이 좀 어색하네요 큐큐 어쨌든! 생성한 Set에 값을 추가하고 제거해 봅시다!
var strSet: Set = ["hi", "i'm", "string", "set"] strSet.insert("nice!") strSet.remove("hi")
Set에서는 insert 함수와 remove 함수를 이용해서 값을 추가하고 제거 할 수 있습니다. 너무 쉽죠?
remove의 return 값은 옵셔널 타입으로 나옵니다!
if strSet.isEmpty { print("It's empty") } else { print("It's not empty") }
또한 array에서와 마찬가지로 isEmpty 값을 확인하여 해당 Set이 비었는지 아닌지를 확인할 수 있습니다.
if strSet.contains("set") { print("yes") }
그리고 대망의 contains...!!!!
사실 이 기능때문에 글을 쓰고있다해도 과언이 아닌데요.
Set의 contains 함수는 무려 O(1)의 시간복잡도로 작동합니다!!
이건 알고리즘 문제를 풀 때 굉장히 유용합니다. array의 contains 함수의 시간복잡도는 O(n)이니까요.
위에서 Set은 고유한 해시 값을 가지는 hashable한 자료형들만 저장할 수 있다고 했죠?!
contains를 작동할 때 이 해시 값을 사용하기 때문에 O(1)의 복잡도로 검사할 수 있다고 합니다.
관련 링크 🔽
https://stackoverflow.com/questions/50240554/swift-set-contains-complexity
Set Operations
Set은 이름에 걸맞게 여러 집합 연산들을 사용할 수 있습니다.
왼쪽 위 그림부터 교집합, 전체에서 교집합 뺀 것,, (? 뭐라고 하져), 합집합, 차집합(a-b) 입니다.
여기는 programming guide의 예제를 그대로 빌려와 볼게요..!
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은 순서가 없는 자료형이다 보니까 순서대로 출력해주기 위해서 전부 .sorted() 해준 것을 볼 수 있네요.
var primes: Set = [2, 3, 5, 7] let favoriteNumber = [5, 7, 15, 21] // array print(primes.intersection(favoriteNumber)) // [5, 7]
위의 예에서는 같은 Set끼리 연산을 해주었는데, 지금과 같이 array나 다른 시퀀스 타입과도 연산이 가능합니다!
Set의 포함관계
또 하나의 Set 자료형의 특징적인 연산(?)은 집합 간의 포함 관계를 확인할 수 있다는 것 입니다.
- isSubset(of:) / isStrictSubset(of:)
let animals: Set = ["🐦", "🐭", "🐶", "🐱", "🐮", "🐔", "🐑", "🐹", "🐰", "🦊"] let houseAnimals: Set = ["🐶", "🐱"] print(houseAnimals.isSubset(of: animals)) // true print(houseAnimals.isStrictSubset(of: animals)) // true print(houseAnimals.isStrictSubset(of: houseAnimals)) // false
isSubset(of:)는 말 그대로 of뒤에 오는 시퀀스 타입의 부분 집합인지를 확인하여 Bool 타입으로 return 하는 함수 입니다.
isStrictSubset(of:)는 부분 집합은 부분 집합이지만, 해당 시퀀스와 완전히 똑같지는 않은 부분집합인지! 이런걸 진부분집합이라고 하던가요,,ㅎㅎ 암튼 그걸 확인해 줍니다.
- isSuperset(of:) / isStrictSuperset(of:)
let animals: Set = ["🐦", "🐭", "🐶", "🐱", "🐮", "🐔", "🐑", "🐹", "🐰", "🦊"] let houseAnimals: Set = ["🐶", "🐱"] print(animals.isSuperset(of: houseAnimals)) // true print(animals.isStrictSuperset(of: houseAnimals)) // true print(animals.isStrictSuperset(of: animals)) // false
Subset을 했으니 Superset도 뭔지 아시겠죠?! 해당 집합이 부모집합인지 (of 뒤의 시퀀스를 완전히 포함하는지) 혹은 진부모집합(?)인지를 확인하는 함수들 입니다.
- isDisjoint(with:)
let houseAnimals: Set = ["🐶", "🐱"] let farmAnimals: Set = ["🐮", "🐔", "🐑", "🐶", "🐱"] let cityAnimals: Set = ["🐦", "🐭"] print(farmAnimals.isDisjoint(with: cityAnimals)) // true print(houseAnimals.isDisjoint(with: farmAnimals)) // false
isDisjoint(with:) 함수는 두 집합 사이에 공통된 부분이 없으면 true, 있으면 false를 반환합니다.
즉, 교집합이 있으면 false! 없으면 true에요 헷갈리지 않게 조심!!
Set과 고차함수 사용하기
https://developer.apple.com/documentation/swift/set
이번에는 apple developer document에 있는 내용을 추가로 살펴볼게요
let primes: Set = [2, 3, 5, 7] let primesSum = primes.reduce(0, +) print(primesSum) // 17
Set 자료형도 배열과 같이 reduce와 같은 고차함수들을 사용할 수 있어요.
let primesStrings = primes.map(String.init) // Array let primesStringsSet = Set(primes.map(String.init)) // Set
또한 map 함수도 사용할 수 있는데요, 여기서 조심할 것은 map 함수를 거치고 나면 반환 값이
배열로 나오기 때문에 Set 자료형을 그대로 쓰고 싶다면 한번 더 Set으로 캐스팅 해줘야 합니다 !
그나저나 map에서 String.init과 같은 형태로 타입캐스팅해 줄 수도 있네요,, 처음 알았네 신기..
여기까지 Set 자료형에 대해서 알아봤습니다. Set 자료형은 contains나 여러 집합 함수들이 많아서 알고리즘 문제 풀 때 잘 알아두면 유용하게 사용할 수 있을 것 같아요!!
그럼 이만 👋
'swift' 카테고리의 다른 글
swift) Initialization (0) 2021.06.19