[Python] 파이썬 셋(set) 사용 방법
파이썬의 셋(set)은 파이썬의 기본 내장 데이터 타입 중 하나입니다.
집합을 표현하는 데이터 타입으로 합집합, 교집합, 차집합 등의 연산을 지원합니다.
셋의 가장 큰 특징은 중복된 값을 허용하지 않는다는 점입니다.
또 하나의 특징은 순서가 없기 때문에 인덱스를 통해 값을 가져올 수 없다는 점입니다.
파이썬의 셋(set) 데이터 타입에 대해 알아보겠습니다.
1. set 생성
파이썬에서 set은 명시적으로 set()을 입력해서 생성할 수 있습니다.
a = set()
b = set([1, 1, 2, 3])
a와 같이 빈 set을 생성하거나 리스트를 통해서 set을 생성할 수 있습니다.
set은 중복을 허용하지 않기 때문에 리스트에 동일한 값이 존재하는 경우 한 개만 set에 입력됩니다.
2. set 연산
파이썬의 set은 집합을 표현하기 때문에 합집합, 교집합, 차집합, 대칭 차집합 연산들을 지원합니다.
연산자나 메소드를 통해 집합 연산의 값을 구할 수 있습니다.
1) 합집합 (union)
A와 B라는 집합이 있을 때 합집합은 다음과 같이 표현됩니다.
파이썬 set의 합집합 역시 양쪽의 값을 모두 포함하며 중복된 값은 한 개만 포함됩니다.
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
print(a.union(b)) # {1, 2, 3, 4, 5, 6}
print(a | b) # {1, 2, 3, 4, 5, 6}
합집합은 union() 메소드나 | 연산자로 구할 수 있습니다.
a와 b의 값이 모두 포함되어 있고 중복된 3, 4는 한 번만 입력되어 있는 것을 확인할 수 있습니다.
2) 교집합 (intersection)
교집합은 A와 B 양쪽 모두에 존재하는 값들만 구합니다.
교집합은 intersection() 메소드나 & 연산자로 구할 수 있습니다.
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
print(a.intersection(b)) # {3, 4}
print(a & b) # {3, 4}
a와 b에 모두 존재하는 3, 4만이 결과로 출력되는 것을 볼 수 있습니다.
3) 차집합 (difference)
차집합은 다음과 같이 표현됩니다.
A에만 존재하는 값들만 결과로 포함시킵니다.
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
print(a.difference(b)) # {1, 2}
print(a - b) # {1, 2}
차집합은 difference() 메소드나 - 연산자로 구할 수 있습니다.
a에서 b에 존재하는 3, 4를 제외시킨 {1, 2}가 결과로 출력됩니다.
4) 대칭 차집합 (symmetric_difference)
대칭 차집합은 다음과 같이 양쪽에 존재하는 값들을 제외한 집합입니다.
가운데 중복되는 값만 제외된 것을 확인할 수 있습니다.
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
print(a.symmetric_difference(b)) # {1, 2, 5, 6}
print(a ^ b) # {1, 2, 5, 6}
대칭 차집합은 symmetric_difference()를 호출하거나 ^ 연산자로 구할 수 있습니다.
a와 b 양쪽에 존재하는 3, 4를 제외한 {1, 2, 5, 6}이 결과로 출력됩니다.
5) 기타 집합 관련 메소드
집합 연산과 관련해서 update로 끝나는 메소드들이 존재합니다.
예를 들어, difference()와 대응하는 difference_update()가 존재합니다.
update가 없는 경우 새로운 set을 생성해서 리턴하기 때문에 기존 set의 값이 변하지 않습니다.
update()가 있는 경우는 리턴이 없고 기존의 set 값을 직접 변경합니다.
각각의 집합 연산에 대응하는 update() 메소드들은 다음과 같습니다.
집합 연산 | 메소드 | 연산자 | update 버전 메소드 | update 버전 연산자 |
합집합 | union() | | | update() | |= |
교집합 | intersection() | & | intersection_update() | &= |
차집합 | difference() | - | difference_update() | -= |
대칭 차집합 | symmetric_difference() | ^ | symmetric_difference_update() | ^= |
예제 코드는 다음과 같으며 새로운 집합을 생성하지 않고 원본 집합의 값을 변경하는 것을 볼 수 있습니다.
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
a.update(b) # a |= b
print(a) # {1, 2, 3, 4, 5, 6}
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
a.intersection_update(b) # a &= b
print(a) # {3, 4}
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
a.difference_update(b) # a -= b
print(a) # {1, 2}
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
a.symmetric_difference_update(b) # a ^= b
print(a) # {1, 2, 5, 6}
그리고 두 집합 사이의 관계를 확인할 수 있는 메소드들도 존재합니다.
먼저 isdisjoint()는 다음과 같이 두 집합에 겹치는 값이 존재하지 않는 경우 True를 리턴합니다.
다음과 같이 겹치는 값이 없는 두 번째 상황({1, 2, 3}, {4, 5, 6})에서 True를 출력합니다.
a = set([1, 2, 3, 4])
b = set([3, 4, 5, 6])
print(a.isdisjoint(b)) # False
a = set([1, 2, 3])
b = set([4, 5, 6])
print(a.isdisjoint(b)) # True
그리고 집합끼리의 포함 관계를 나타내는 상위집합(superset)과 부분집합(subset) 관계도 구할 수 있습니다.
a = set([1, 2, 3, 4])
b = set([2, 3])
print(a.issuperset(b)) # True
print(a >= b) # True
print(b.issubset(a)) # True
print(b <= a) # True
여기서는 a가 b를 완전히 포함하고 있기 때문에 a는 b의 상위집합(superset)입니다.
그리고 b는 a의 부분집합(subset)이라고도 볼 수 있습니다.
issuperset()은 >= 연산자로도 표현이 가능하고 issubset()은 <= 연산자로 표현이 가능합니다.
issuperset()과 issubset()은 a와 b가 완전히 동일한 값일 때도 True를 리턴합니다.
a와 b가 같은 상황을 제외한 진부분집합(proper subset)과 진상위집합(proper superset) 역시 구할 수 있습니다.
부분집합과 상위집합을 구하는 전체 메소드와 연산자는 다음과 같습니다.
집합 관계 | 메소드 | 연산자 |
부분집합 | issubset() | <= |
상위집합 | issuperset() | >= |
진부분집합 | 없음 | < |
진상위집합 | 없음 | > |
연산자와 메소드를 통해 집합들의 관계와 연산 결과를 쉽게 구할 수 있습니다.
3. set 길이 확인
set은 순서가 없는 데이터 타입이지만 길이를 구하는 것은 가능합니다.
a = set([1, 2, 3, 4])
print(len(a)) # 4
다른 타입과 동일한 방법으로 len()을 통해 길이를 얻을 수 있습니다.
4. set 값 추가/삭제
set은 값을 추가하거나 삭제하기 위한 다양한 메소드가 있습니다.
값을 추가할 때는 add() 메소드를 호출하면 됩니다.
a = set([1, 2, 3, 4])
a.add(5)
print(a) # {1, 2, 3, 4, 5}
특정 값을 한 개 삭제할 때는 discard()와 remove()를 호출하면 되는데 약간의 차이가 있습니다.
a = set([1, 2, 3, 4])
a.discard(4)
a.discard(4)
a.remove(3)
# a.remove(3) # KeyError
remove()는 set 안에 없는 값을 삭제하려고 할 때 KeyError를 발생시킵니다.
discard()는 값이 없는 경우에도 에러가 발생하지 않습니다.
만약 값의 유무와 상관없이 삭제를 시도하고 싶은 경우 discard()를 호출하면 됩니다.
그리고 랜덤하게 값을 한 개 삭제하고 동시에 리턴받고 싶은 경우는 pop()을 호출하면 됩니다.
a = set([1, 2, 3, 4])
print(a.pop())
print(a)
pop()이 값을 한 개 리턴하고 그 값이 a에서 삭제된 것을 확인할 수 있습니다.
마지막으로 모든 값을 삭제하고 싶은 경우 clear()를 호출하면 됩니다.
a = set([1, 2, 3, 4])
a.clear()
print(a) # set()
모든 값들이 지워진 것을 확인할 수 있습니다.
5. 기타 set 메소드
마지막으로 copy() 메소드를 통해 동일한 set을 새로 생성할 수 있습니다.
a = set([1, 2, 3, 4])
b = a.copy()
b.add(5)
print(a) # {1, 2, 3, 4}
print(b) # {1, 2, 3, 4, 5}
copy()로 복사한 set은 한 쪽을 변경했을 때 다른 쪽이 영향을 받지 않는 것을 확인할 수 있습니다.
파이썬의 set은 집합 연산에 특화된 데이터 타입입니다.
또한 중복된 값을 허용하지 않는 특성때문에 중복 값을 걸러내거나 하는데 활용되기도 합니다.