-
Swift - SetProgramming/Swift 2021. 10. 14. 14:45
안녕하세요 Beepeach 입니다 :)
오늘은 Set에 대해서 공부해보도록 하겠습니다.
Set을 번역하면 집합이죠??
수학시간에 배웠던 집합을 생각하면 됩니다. 그리고 그 집합들이 가지고 있던 연산도 쉽게 구현되어 있습니다.
Set
Set과 Array는 비슷하지만 큰 차이는 unordered와 unique elements에 있습니다.
정렬되어있지 않고 element가 중복되지 않습니다.
제네릭을 보면 Element가 Hashable 프로토콜을 채용하고 있어야 합니다.
만약 element가 hashable을 채용하고 있지 않다면 set으로 만들 수 없습니다.
하지만 string, numeric, boolean 등 대부분의 기본 타입은 hashable 프로토콜을 채용하고 있으니 크게 걱정하지 않아도 됩니다.
Create
Set을 생성하는 방법은 간단합니다.
Array literal을 사용하면 됩니다. 하지만 주의할 점은 타입을 지정해주지 않으면 array가 생성됩니다.
Set <Int>와 같이 element의 type도 같이 적어주거나 그냥 Set만 적어서 type annotation을 해주면 set을 만들 수 있습니다.
set을 확인해보면 1, 2, 3, 10이 여러 개 중복이 되지만 하나씩만 들어가게 됩니다.
정말 4개만 들어가 있는지 확인해 보겠습니다.
Read
Set도 Collection이기 때문에 count와 isEmpty 속성을 사용할 수 있습니다.
set의 count를 확인해보니 9 가아니라 4인 것을 확인할 수 있습니다.
contains(_:) 메서드는 element가 존재하는지 확인합니다.
만약 element가 존재한다면 true를 리턴합니다.
update
Set의 element를 추가하는 방법은 두 가지 메서드를 사용합니다.
먼저 insert(_:) 메서드를 보겠습니다.
리턴 값을 보면 tuple입니다.
파라미터로 전달한 element가 set에 이미 존재한다면 (false, oldMember)가 리턴이 됩니다.
oldMember는 newMember와 동일한 값입니다.
만약 존재하지 않아서 insert가 됐다면 (true, newMember)가 리턴이 됩니다.
빈 Set<String>을 만들고 "Apple"을 두 번 insert 해보았습니다.
처음에는 true가 두 번째는 false가 리턴되는 것을 확인할 수 있습니다.
이제 그다음 메서드인 update(with:) 메서드를 보겠습니다.
겉으로 보기에 큰 차이점은 리턴 값이 다르다는 점입니다.
Element?를 리턴하네요.
Element가 set에 존재하지 않아서 update가 됐다면 nil을 리턴합니다.
만약 존재해서 실패한다면 oldMember를 리턴합니다.
insert(_:)와 마찬가지로 oldMember는 newMember와 같습니다.
그럼 이런 생각이 들 수 있습니다. (이 부분은 중요하지 않으니 넘어가셔도 좋습니다!)
그냥 둘 중에 하나만 있어도 될 거 같은데 왜 두 개로 나눠놨지??
update(with:)의 설명을 자세히 보시면 답이 있습니다.
Unconditionally!! 무조건!!
update(with:) 메서드는 element를 무조건 삽입한다는 게 다릅니다.
여기서 헷갈리시면 안되는 게 존재해도 무조건 삽입해서 element가 2개가 되는게 아닙니다.
이미 같은 element가 존재했다면 oldMember를 newMember로 교체하게 됩니다.
이 부분은 일반적으로 우리가 set을 그냥 사용할 때는 차이가 없어 보입니다.
그럼 언제 차이가 보일까요??
예제를 통해 확인해보겠습니다.
새로운 타입인 MyType을 만들었습니다.
그리고 set은 hashable 프로토콜을 채용한 타입만 올 수 있으므로 hashable 프로토콜을 채용하고 hashvalue는 모든 인스턴스가 100을 가지도록 했습니다.
그리고 MyType의 인스턴스들의 비교는 hashValue를 통해서 하도록 만들었습니다.
그런데 hashValue가 모두 100이죠?? 그럼 모든 인스턴스는 data가 다르더라도 같은 값이 됩니다.
apple, google, samsung 세 인스턴스를 생성하고 myTypeSet에 넣었습니다.
그럼 세 가지가 모두 중복처리되어 한 가지만 들어가게 되고 count를 세어보면 1개인 것을 확인할 수 있습니다.
여기에 ms 인스턴스를 새로 만들어서 insert를 하게 된다면??
apple이 존재하므로 insert는 실패하고 (false, {hashValue 100, data "Apple"})가 리턴됩니다.
기존에 있던 oldValue가 그대로 담겨있는 거죠.
하지만 update(with:)는 element가 같아도 무조건 oldMember를 newMember로 교체한다고 했죠??
실제로 update(with:ms)를 하니까 같은 element이지만 oldMember가 numMember로 교체되었습니다.
Apple이 아닌 MS가 들어간 모습을 확인할 수 있습니다.
delete
Delete는 dictionary나 array와 비슷합니다.
remove(_:) 메서드와 removeAll(keepingCapacity:) 메서드를 사용해서 제거할 수 있습니다.
remove(_:) 메서드는 해당 element 존재하면 삭제하고 삭제된 element를 리턴해줍니다.
만약 존재하지 않는다면 nil을 리턴합니다.
Compare
Set의 비교는 정렬되어 있지 않기 때문에 dictionary와 비슷한 부분이 있습니다.
비슷한 부분부터 살펴보고 가겠습니다.
비교 연산자를 사용하면 중복되는 수와 순서와 상관없이 비교를 하게 됩니다.
그리고 elementsEqual(_:) 메서드를 사용하면 정렬이 되어있지 않기 때문에 매번 결괏값이 달라질 수 있습니다.
Set은 집합이고 집합 연산을 쉽게 도와주는 메서드가 많이 존재합니다.
isSubset(of:) 메서드는 이 메서드를 호출한 set이 파라미터로 전달된 set의 subset인지 체크합니다.
subset이 있으니 superset도 마찬가지로 존재합니다.
그리고 strictSubset, strictSuperset 진부분 집합도 존재합니다.
또한 disjoint 서로소 집합도 제공을 합니다.
Combine
마지막으로 집합 연산에 중요한 합집합, 교집합, 여집합, 차집합을 구하는 기능을 제공하는 메서드를 살펴보겠습니다.
union(_:) 메서드는 두 set의 합집합을 새로운 set으로 리턴해줍니다.
새로운 set을 리턴하지 않고 호출한 set을 변경시키는 메서드도 존재합니다.
formUnion(_:) 메서드는 두 set의 합집합을 새롭게 리턴해주는 게 아니라 호출한 메서드를 변경시킵니다.
나머지 집합 연산도 비슷하게 구현되어있습니다.
다만 차집합만 모습이 살짝 다릅니다.
지금까지 보던 메서드들과 비슷하게 메서드 이름에 ing가 붙어있습니다.
subtracting(_:) 메서드는 원본을 변경하지 않고 새로운 set을 리턴해주는 메서드입니다.
그럼 원본을 바꿔주는 메서드는 바로 유추할 수 있겠죠??
subtract(_:) 메서드는 원본을 변경하는 메서드입니다.
참고자료
https://docs.swift.org/swift-book/LanguageGuide/CollectionTypes.html
https://developer.apple.com/documentation/swift/set
728x90'Programming > Swift' 카테고리의 다른 글
Swift - Enumeration (열거형) (0) 2021.10.15 Swift - KeyValuePairs (0) 2021.10.14 Swift - Dictionary (0) 2021.10.08 Swift - Array (0) 2021.08.30 Swift - Foundation Collection & Swift Collection (0) 2021.08.28