티스토리 뷰

Apple/Swift

Swift의 집합 개념과 연산

doyeonjeong_ 2022. 9. 12. 17:13

집합은 같은 타입의 서로 다른 값을 중복 없이 저장할 때 사용하는 집단 자료형이다.

배열과 매우 유사하지만 다른 점은 순서가 없다는 것과 중복 값이 없다는 것!

 

집합에 저장할 데이터 타입은 해시 연산을 할 수 있는 타입이어야 한다.

왜냐하면 내부적으로 해시(Hash) 연산의 결과값을 이용하여 데이터를 저장하기 때문이다.


해시 연산(Hash Algorithm)?

임의의 입력 값을 고정 길이의 데이터 크기로 변환해주는 알고리즘이다.

너무 길거나 너무 짧은 값이라도 고정 길이의 데이터로 저장이 가능하다!

주로 복호화가 필요 없는 암호화에 많이 사용된다고 한다.

많이 알려진 해시 알고리즘에는 MD5, SHA1, SHA256 등이 있다.


Swift에서 집합을 정의하는 방법 2가지

1. 초기값을 사용하여 바로 정의

2. 빈 집합을 선언하고 초기화


1. 초기값을 사용하여 집합을 정의하는 방법

값으로 사용되는 데이터 리터럴은 배열과 동일하다. 즉, 배열 데이터를 사용해서 정의한다.

그냥 값만 입력하면 배열로 인식하기 때문에 Set이라는 정의하는 과정이 필요하다.

var genres: Set = ["Classic", "Pop", "Jazz"]

2. 빈 집합을 선언하고 초기화

var genres = Set<Setting>()

genres.insert("Classic")
genres.insert("Pop")
genres.insert("Jazz")

집합 순회 탐색

for ~ in 구문 사용

for g in genres {
	print("\(g)")
}

[출력]
Classic
Pop
Jazz

 

sort( ) 메소드로 정렬이 가능하다.

print(genres.sorted()) //["Classic", "Jazz", "Pop"]

자주 사용하는 메서드 3가지

remove : 해당 value 삭제

집합에 추가되지 않은 값을 remove하면 nil이 반환된다.

if let removedItem = genres.remove("Pop") {
    print("삭제한 장르 : \(removedItem)")
    print("남은 장르 : \(genres)")
} else {
    print("삭제할 값 없음")
}

[출력]
삭제한 장르 : Pop
남은 장르 : ["Jazz", "Classic"]


if let removedItem = genres.remove("?") {
    print("삭제한 장르 : \(removedItem)")
    print("남은 장르 : \(genres)")
} else {
    print("삭제할 값 없음")
}

[출력]
삭제할 값 없음

removeAll() : 모든 요소 삭제

genres.removeAll()

if genres.isEmpty {
    print("삭제 완료")
} else {
    print("삭제할 값 남았음") // 출력됨
}

contains : 요소 여부 확인

if genres.contains("Pop") {
    print("Pop 있음") // 출력
} else {
    print("Pop 없음")
}

집합 연산

var odds: Set = [1, 3, 5, 7, 9]  // 홀수
let evens: Set = [0, 2, 4, 6, 8] // 짝수
let primes: Set = [2, 3, 5, 7]   // 소수

1. 합집합

odds.union(evens).sorted() // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

2. 차집합

odds.subtract(primes) // {1, 9}
odds.sorted() // [1, 9]

다른 세가지 집합 연산은 각 집합에 영향을 주지 않고 새로운 집합을 반환하지만

차집합은 연산이 실행되면서 정말 값을 지우기 때문에 다르게 표시된다. 따라서 상수로 선언하면 에러가 발생한다.

즉, { } 이 안에 있는 값은 연산되고 남은 값이라는 걸 알 수 있다.

아래 한번 더 sorted()를 통해 출력한 이유는 반환된 값이 없기 때문에 subtract와 동시에 sorted()를 쓸 수 없어서이다.

 

3. 교집합

odds.intersection(evens).sorted() // []
odds.intersection(primes).sorted() // [1, 2, 9]

4. 대칭차 🤔

odds.symmetricDifference(primes).sorted() // [1, 2, 9]

https://j1w2k3.tistory.com/956

난 여기서 대칭차라는 말을 처음들어봤다. 양쪽 집합에서도 서로 중복되지 않는 결과들만 모아 집합으로 반환된다.

 

 

한번에 모아보기

더보기
var odds: Set = [1, 3, 5, 7, 9]  // 홀수
let evens: Set = [0, 2, 4, 6, 8] // 짝수
let primes: Set = [2, 3, 5, 7]   // 소수

// 1. 합집합
odds.union(evens).sorted() // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

// 2. 차집합
odds.subtract(primes) // {1, 9}
odds.sorted() // [1, 9]

// 3. 교집합
odds.intersection(evens).sorted() // []
odds.intersection(primes).sorted() // [1, 2, 9]

// 4. 대칭차
odds.symmetricDifference(primes).sorted() // [1, 2, 9]

부분집합과 포함관계 연산

부분집합은 꼭 한쪽이 반드시 더 커야지만 성립하는 관계가 아니다.

A == B 처럼 양쪽 집합의 크기와 값이 동일하더라도 서로의 부분집합이라고 불릴 수 있다.

이를 프로그래밍 관점에서도 파악하는 메서드가 존재하는데 대표적으로 5가지가 있다.

let A: Set = [1, 3, 5, 7, 9]
let B: Set = [3, 5]
let C: Set = [5, 3]
let D: Set = [2, 4, 6]

// 1. B는 A의 부분집합인가?
B.isSubset(of: A) // true

// 2. A는 B의 상위집합인가?
A.isSuperset(of: B) // true

// 3. C는 A의 확실한 부분집합인가?
C.isStrictSubset(of: A) // true

// 4. C는 B의 확실한 부분집합인가?
C.isStrictSuperset(of: B) // false

// 5. A와 D에는 아무런 공통값이 없는가?
A.isDisjoint(with: D) // true

isSubset, isSuperset은 양쪽 집합의 크기가 같더라도 부분집합 또는 상위집합으로 인식하지만

isStrictSubset, isStrictSuperset은 정확히 작은 부분집합인지, 큰 상위집합인지 판단한 결과를 반환한다.


배열의 중복 값을 제거하는 방법

과정을 전체적으로 나타내면 3줄이 되지만

var A = [1, 3, 5, 7, 9, 5, 7, 9, 5, 7, 9, 1, 3, 5]
let B = Set(A) // {9, 3, 1, 5, 7}
A = Array(B) // [9, 3, 1, 5, 7]
A = Array(Set(A))

이렇게 한 줄로 처리하면 간편하다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함