Logo

파이썬 세트(set) 완벽 가이드

세트(set)는 파이썬에서 고유한 값들의 집합을 다루는 자료구조입니다. 이를 활용하면 데이터 중복을 제거하고 유일한 값들을 효과적으로 관리할 수 있는데요.

이번 포스팅에서는 다양한 예제를 통해서 파이썬의 세트을 어떻게 사용하는지 아주 꼼꼼하고 차근차근 알아보도록 하겠습니다.

세트 자료구조

먼저, 파이썬와 별개로 자료구조로서의 집합이라고도 불리는 세트에 대해서 가볍게 개념 정리를 하고 넘어가면 좋을 것 같습니다.

세트(set)는 한마디로 순서가 없는 중복되지 않은 데이터의 집합인데요. 리스트(list)과 차이점을 이해하는 것이 무엇보다 중요합니다.

리스트는 데이터를 순서있게 저장합니다. 그래서 인덱스(index)를 통해서 특정 위치에 저장되어 있는 데이터에 접근이 가능하죠. 그리고 리스트에는 동일한 값을 여러 번 저장할 수 있습니다. 값이 동일하더라도 인덱스가 틀리기 때문에 데이터의 중복이 문제되지 않습니다.

반면에 세트는 얼핏 보기에는 리스트과 비슷해보일 수 있지만 사실 결이 아주 다른 자료구조입니다. 우선 세트는 데이터를 순서없이 저장합니다. 따라서 리스트처럼 인덱스를 통해서 접근할 수가 없습니다. 그리고 세트는 중복된 데이터를 허용하지 않습니다. 즉, 기존에 세트에 있는 값을 또 추가하면 아무 효력이 발생하지 않습니다.

파이썬에서 가장 널리 사용되는 자료형인 리스트(list)에 대해서는 관련 포스팅을 참고바랍니다.

세트 생성

세트는 여러 가지 방법으로 생성할 수 있는데요. 가장 간편한 방법은 중괄호({}) 안에 여러 원소를 쉼표(,)로 구분해서 나열해주는 것입니다.

>>> {'A', 'B', 'C'}
{'A', 'B', 'C'}

하지만 빈 세트를 생성할 때는 중괄호를 쓸 수 없으니 주의 바랍니다. 빈 중괄호는 파이썬에서 사전(dictionary)로 인식되기 때문입니다.

>>> {}
{} # dict

대신에 빈 세트를 생성할 때는 set() 내장 클래스를 사용해야 합니다.

>>> set()
set()

값 추가

세트에 새로운 값을 추가할 때는 add() 메서드를 사용하는데요. 위에서 설명드린 것처럼 세트에는 중복된 값이 추가되지 않으며, 유일한 값만 저장됩니다.

>>> num_set = set()
>>> num_set.add(1)
>>> num_set.add(2)
>>> num_set.add(3)
>>> num_set
{1, 2, 3}

값 삭제

세트의 remove() 메서드를 사용하면 세트로 부터 특정 값을 삭제할 수 있습니다.

>>> num_set = {1, 2, 3}
>>> num_set.remove(1)
>>> num_set
{2, 3}
>>> num_set.remove(3)
>>> num_set
{3}

remove() 메서드의 인자로 넘기는 값이 세트에 존재하지 않는다면 오류가 발생합니다.

>>> num_set.remove(1) # KeyError: 1

discard() 메서드를 사용하면 값이 세트에 존재하지 않아도 오류가 발생하지 않습니다. 대신 세트에 아무 일도 일어나지 않죠.

>>> num_set.discard(1)
>>> num_set
{3}

값 존재 여부 확인

in 연산자를 사용하면 특정 값이 세트에 존재하는지 쉽게 확인 할 수 있습니다.

>>> char_set = {'A', 'B', 'C'}
>>> 'B' in char_set
True
>>> 'D' in char_set
False
>>> 'D' not in char_set
True

따라서 if 조건문과도 자연스럽게 함께 사용할 수 있습니다.

>>> if 'B' in char_set:
...     print('B는 세트에 존재합니다.')
... else:
...     print('B는 세트에 존재하지 않습니다.')
...
B는 세트에 존재합니다.

당연히 3항 연산자(ternary operator)와도 궁합이 잘 맞겠죠?

>>> 'D 있음' if 'D' in char_set else 'D 없음'
'D 없음'

모든 값 제거

세트에 저장된 모든 값을 제거하려면 clear() 메서드를 호출합니다.

>>> char_set = {'A', 'B', 'C'}
>>> char_set.clear()
>>> char_set
set()

세트 순회

세트에 저장되어 있는 모든 값을 순회하고 싶을 때는 어떻게 해야 할까요? 이 때는 for 루프문 안에서 in 연산자를 사용하면 됩니다.

>>> char_set = {'A', 'B', 'C'}
>>> for char in char_set:
...    print(char)
...
B
C
A

세트는 값을 순서없이 저장하기 때문에 반복문 안에서 어떤 값이 먼저 나올지는 예측할 수 없습니다. 값의 순서가 중요하다면 세트 대신에 리스트를 쓰셔야 합니다.

세트의 동등성

맨 처음에 세트는 순서가 없이 데이터를 저장한다고 말씀드렸는데요. 그래서 값이 순서가 다르더라도 같은 값을 담고 있다면 동일한 세트로 취급이 됩니다.

>>> {'A', 'B', 'C'} == {'A', 'C', 'B'}
True

뿐만 아니라, 중복된 값도 무시되어 비교되겠죠?

>>> {'A', 'B'} == {'A', 'A', 'B', 'B'}
True

리스트을 세트로 변환

실제로 코딩을 하다보면 기존에 존재하는 리스트로 부터 새로운 세트를 만들어야 하는 경우가 빈번한데요. 이 때는 set() 생성자의 인자로 리스트를 넘기면 됩니다.

>>> nums = [1, 2, 2, 3, 3, 3]
>>> num_set = set(nums)
>>> num_set
{1, 2, 3}

여기서 중요한 부분은 이렇게 리스트로 부터 세트를 만들어내면 중복 값이 모두 제거된다는 것입니다. 중복 값을 유지해야하는 상황에서는 절대로 리스트을 세트로 변환하면 안되겠죠?

세트를 리스트로 변환

그럼 반대로 세트를 리스트로 변환해야 할 때는 어떻게 해야 할가요? 이 때는 list() 생성자의 인자로 세트를 넘기면 됩니다.

>>> num_set = {1, 2, 3}
>>> nums = list(num_set)
>>> nums
[1, 2, 3]

리스트에서 중복 값 제거

세트는 중복 값을 허용하지 않기 때문에, 리스트에서 중복된 값을 제거하는 데에 매우 유용하게 활용될 수 있습니다.

>>> numbers = [1, 2, 2, 3, 4, 4, 5]
>>> unique_numbers = list(set(numbers))
>>> unique_numbers
[1, 2, 3, 4, 5]

문자열에서 중복 문자 제거

비슷한 방법으로 세트를 이용해서 문자열에서 중복 문자를 제거할 수도 있는데요.

>>> chars = "AAABBC"
>>> unique_chars = "".join(set(chars))
>>> unique_chars
'ACB'

역시 문자의 순서는 예측할 수 없습니다.

집합 연산

여러 개의 세트를 상대로 다음과 같이 합집합, 교집합, 차집합을 구할 수 있습니다.

>>> set1 = {1, 2, 3, 4, 5}
>>> set2 = {4, 5, 6, 7, 8}
# 합집합
>>> union = set1 | set2
>>> union
{1, 2, 3, 4, 5, 6, 7, 8}
# 교집합
>>> intersection = set1 & set2
>>> intersection
{4, 5}
# 차집합
>>> difference = set1 - set2
>>> difference
{1, 2, 3}

전체 코드

본 포스팅에서 제가 작성한 전체 코드는 아래에서 직접 확인하고 실행해보실 수 있습니다.

https://dales.link/lrr

마치면서

지금까지 파이썬에서 세트를 사용하는 방법에 대해서 자세히 살펴보았습니다. 이 정도만 숙지하시면 실전 프로그래밍에서에서 큰 부족함없이 세트를 활용하실 수 있으실 거에요. 본 포스팅을 통해서 세트 자료구조를 제대로 이해하고, 파이썬의 세트가 제공하는 기능들을 잘 활용하여 보다 효율적이고 간결한 코드를 작성할 수 있으셨으면 좋겠습니다.