Skip to content

16. 세트(Set)


1. 키워드

  • 세트(Set)


2. 세트 사용하기

  • 파이썬은 집합을 표현하는 세트(Set)라는 자료형을 제공한다.
  • 따라서 세트는 합집합, 교집합, 차집합 등의 연산이 가능하다.


3. 세트 만들기

  • 세트는 {}(중괄호) 안에 값을 저장하며 각 값은 ,(콤마)로 구분해 준다.


세트 = {값1, 값2, 값3}
>>> fruits = {"strawberry", "grape", "orange", "pineapple", "cherry"}

>>> fruits
{'pineapple', 'orange', 'grape', 'strawberry', 'cherry'}


  • 세트는 요소의 순서가 정해져 있지 않다.
  • 따라서 세트를 출력해 보면 매번 요소의 순서가 다르게 나온다.
  • 또한, 세트에 들어가는 요소는 중복될 수 없다.


  • 다음과 같이 세트에 "orange"를 두 개 넣어도 실제로는 한 개만 들어간다.


>>> fruits = {"orange", "orange", "cherry"}

>>> fruits
{'cherry', 'orange'}


  • 특히 세트는 리스트, 튜플, 딕셔너리와는 달리 [](대괄호)로 특정 요소만 출력할 수는 없다.


>>> fruits = {"strawberry", "grape", "orange", "pineapple", "cherry"}

>>> print(fruits[0]) # TypeError: 'set' object does not support indexing

>>> fruits["strawberry"] # TypeError: 'set' object is not subscriptable


1) 세트에 특정 값이 있는지 확인하기

  • 세트에 특정 값이 있는지 확인하려면 지금까지 리스트, 튜플, 딕셔너리에 사용했던 in 연산자를 사용하면 된다.


 in 세트
>>> fruits = {"strawberry", "grape", "orange", "pineapple", "cherry"}

>>> "orange" in fruits
True
>>> "peach" in fruits
False


  • 반대로 in 앞에 not을 붙이면 특정 값이 없는지 확인한다.


 not in 세트
>>> "peach" not in fruits
True
>>> "orange" not in fruits
False


2) set을 사용하여 세트 만들기

  • 이번에는 set을 사용하여 세트를 만들어보자.


set(반복가능한객체)


  • set에는 반복 가능한 객체(Iterable)를 넣는다.


>>> a = set("apple")

>>> a
{'e', 'l', 'a', 'p'}


  • 그리고 set(range(5))와 같이 숫자를 만들어내는 range를 사용하면 0부터 4까지 숫자를 가진 세트를 만들 수 있다.


>>> b = set(range(5))

>>> b
{0, 1, 2, 3, 4}


  • 빈 세트는 c = set()과 같이 set에 아무것도 지정하지 않으면 된다.


>>> c = set()

>>> c
set()


  • 단, 세트가 {}를 사용한다고 해서 c = {}와 같이 만들면 빈 딕셔너리가 만들어지므로 주의해야 한다.


>>> c = {}
>>> type(c)
<class 'dict'>

>>> c = set()
>>> type(c)
<class 'set'>


세트 안에 세트 넣기

  • 세트는 리스트, 딕셔너리와 달리 세트 안에 세트를 넣을 수 없다.


>>> a = {{1, 2}, {3, 4}} # TypeError: unhashable type: 'set'


프로즌 세트

  • 파이썬은 내용을 변경할 수 없는 세트도 제공한다.


프로즌세트 = frozenset(반복가능한객체)
>>> a = frozenset(range(10))

>>> a
frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9})


  • frozenset은 뒤에서 설명할 집합 연산과 메서드에서 요소를 추가하거나 삭제하는 연산, 메서드는 사용할 수 없다.


  • 즉, 다음과 같이 frozenset의 요소를 변경하려고 하면 에러가 발생한다.


>>> a = frozenset(range(10))

>>> a |= 10 # TypeError: unsupported operand type(s) for |=: 'frozenseet' and 'int'

>>> a.update({10}) # AttributeError: 'frozenset' object has no attribute 'update'


  • frozenset은 세트 안에 세트를 넣고 싶을 때 사용한다.


  • 다음과 같이 frozensetfrozenset을 중첩해서 넣을 수 있으며, 일반 set은 넣을 수 없다.


>>> frozenset({frozenset({1, 2}), frozenset({3, 4})})
frozenset({frozenset({1, 2}), frozenset({3, 4})})


4. 집합 연산 사용하기

  • 집합 연산은 파이썬의 산술 연산자와 논리 연산자를 활용한다.


  • | 연산자는 합집합(Union)을 구하며 OR 연산자 |를 사용하고, set.union 메서드와 동작이 같다.


세트1 | 세트2
set.union(세트1, 세트2)
>>> a = {1, 2, 3, 4}
>>> b = {3, 4, 5, 6}

>>> a | b
{1, 2, 3, 4, 5, 6}

>>> set.union(a, b)
{1, 2, 3, 4, 5, 6}


001


  • & 연산자는 교집합(Intersection)을 구하며 AND 연산자 &를 사용하고, set.intersection 메서드와 동작이 같다.


세트1 & 세트2
set.intersection(세트1, 세트2)
>>> a & b
{3, 4}

>>> set.intersection(a, b)
{3, 4}


002


  • - 연산자는 차집합(Difference)을 구하며 뺄셈 연산자 -를 사용하고, set.difference 메서드와 동작이 같다.


세트1 - 세트2
set.difference(세트1, 세트2)
>>> a - b
{1, 2}

>>> set.difference(a, b)
{1, 2}


003


  • ^ 연산자는 대칭차집합(Symmetric Difference)을 구하며 XOR 연산자 ^를 사용하고, set.symmetric_difference 메서드와 동작이 같다.


세트1 ^ 세트2
set.symmetric_difference(세트1, 세트2)
>>> a ^ b
{1, 2, 5, 6}

>>> set.symmetric_difference(a, b)
{1, 2, 5, 6}


004


1) 집합 연산 후 할당 연산자 사용하기

  • 세트 자료형에 |, &, -, ^ 연산자와 할당 연산자 =을 함께 사용하면 집합 연산의 결과를 변수에 다시 저장(할당)한다.


  • |=은 현재 세트에 다른 세트를 더하며 update 메서드와 같다.


세트1 |= 세트2
세트1.update(세트2)
>>> a = {1, 2, 3, 4}
>>> a |= {5}
>>> a
{1, 2, 3, 4, 5}

>>> a = {1, 2, 3, 4}
>>> a.update({5})
>>> a
{1, 2, 3, 4, 5}


  • &=은 현재 세트와 다른 세트 중에서 겹치는 요소만 현재 세트에 저장하며 intersection_update 메서드와 같다.


세트1 &= 세트2
세트1.intersection_update(세트2)
>>> a = {1, 2, 3, 4}
>>> a &= {0, 1, 2, 3, 4}
>>> a
{1, 2, 3, 4}

>>> a = {1, 2, 3, 4}
>>> a.intersection_update({0, 1, 2, 3, 4})
>>> a
{1, 2, 3, 4}


  • -=은 현재 세트에서 다른 세트를 빼며 difference_update 메서드와 같다.


세트1 -= 세트2
세트1.difference_update(세트2)
>>> a = {1, 2, 3, 4}
>>> a -= {3}
>>> a
{1, 2, 4}

>>> a = {1, 2, 3, 4}
>>> a.difference_update({3})
>>> a
{1, 2, 4}


  • ^=은 현재 세트와 다른 세트 중에서 겹치지 않는 요소만 현재 세트에 저장하며 symmetric_difference_update 메서드와 같다.


세트1 ^= 세트2
세트1.symmetric_difference_update(세트2)
>>> a = {1, 2, 3, 4}
>>> a ^= {3, 4, 5, 6}
>>> a
{1, 2, 5, 6}

>>> a = {1, 2, 3, 4}
>>> a.symmetric_difference_update({3, 4, 5, 6})
>>> a
{1, 2, 5, 6}


2) 부분집합과 상위집합 확인하기

  • 세트는 부분집합, 진부분집합, 상위집합, 진상위집합과 같이 속하는 관계를 표현할 수도 있다.
  • 현재 세트가 다른 세트의 (진)부분집합 또는 (진)상위집합인지 확인할 때는 세트 자료형에 부등호와 등호를 사용한다.


  • <=은 현재 세트가 다른 세트의 부분집합(Subset)인지 확인하며 issubset 메서드와 같다.


현재세트 <= 다른세트
현재세트.issubset(다른세트)
>>> a = {1, 2, 3, 4}

>>> a <= {1, 2, 3, 4}
True

>>> a.issubset({1, 2, 3, 4, 5})
True


005


  • <은 현재 세트가 다른 세트의 진부분집합(Proper Subset)인지 확인하며 메서드는 없다.


현재세트 < 다른세트
>>> a = {1, 2, 3, 4}

>>> a < {1, 2, 3, 4, 5}
True


006


  • >=은 현재 세트가 다른 세트의 상위집합(Superset)인지 확인하며 issuperset 메서드와 같다.


현재세트 >= 다른세트
현재세트.issuperset(다른세트)
>>> a = {1, 2, 3, 4}

>>> a >= {1, 2, 3, 4}
True

>>> a.issuperset({1, 2, 3, 4})
True


007


  • >은 현재 세트가 다른 세트의 진상위집합(Proper Superset)인지 확인하며 메서드는 없다.


현재세트 > 다른세트
>>> a = {1, 2, 3, 4}

>>> a > {1, 2, 3}
True


008


3) 세트가 같은지 다른지 확인하기

  • 세트는 == 연산자를 사용하여 서로 같은지 확인할 수 있다.


>>> a = {1, 2, 3, 4}

>>> a == {1, 2, 3, 4}
True
>>> a == {4, 2, 1, 3}
True


  • != 연산자는 세트가 다른지 확인한다.


>>> a = {1, 2, 3, 4}

>>> a != {1, 2, 3}
True


4) 세트가 겹치지 않는지 확인하기

  • isdisjoint는 현재 세트가 다른 세트와 겹치지 않는지 확인한다.


현재세트.isdisjoint(다른세트)
>>> a = {1, 2, 3, 4}

>>> a.isdisjoint({5, 6, 7, 8})
True
>>> a.isdisjoint({3, 4, 5, 6})
False


5. 세트 조작하기

  • 이번에는 세트를 조작하는 메서드와 세트의 길이(요소 개수)를 구하는 방법을 알아보자.


1) 세트에 요소 추가하기

  • add(요소)는 세트에 요소를 추가한다.


>>> a = {1, 2, 3, 4}

>>> a.add(5)

>>> a
{1, 2, 3, 4, 5}


2) 세트에서 특정 요소를 삭제하기

  • remove(요소)는 세트에서 특정 요소를 삭제하고 요소가 없으면 에러를 발생시킨다.


>>> a.remove(3)

>>> a
{1, 2, 4, 5}


  • discard(요소)는 세트에서 특정 요소를 삭제하고 요소가 없으면 그냥 넘어간다.


>>> a.discard(2)
>>> a
{1, 4, 5}

>>> a.discard(3)
>>> a
{1, 4, 5}


3) 세트에서 임의의 요소 삭제하기

  • pop()은 세트에서 임의의 요소를 삭제하고 해당 요소를 반환한다.
  • 만약 요소가 없으면 에러를 발생시킨다.


>>> a = {1, 2, 3, 4}

>>> a.pop()
1

>>> a
{2, 3, 4}


4) 세트의 모든 요소를 삭제하기

  • clear()는 세트에서 모든 요소를 삭제한다.


>>> a.clear()

>>> a
set()


5) 세트의 요소 개수 구하기

  • len(세트)는 세트의 요소 개수(길이)를 구한다.


>>> a = {1, 2, 3, 4}

>>> len(a)
4


6. 세트의 할당과 복사

  • 세트도 리스트, 딕셔너리처럼 할당과 복사의 차이점이 있다.


>>> a = {1, 2, 3, 4}

>>> b = a


  • b = a와 같이 세트를 다른 변수에 할당하면 세트는 두 개가 될 것 같지만 실제로는 세트가 한 개이다.


  • abis 연산자로 비교해 보면 True가 나오며, 이는 변수 이름만 다를 뿐 세트 ab는 같은 객체라는 것을 의미한다.


>>> a is b
True


  • ab는 같으므로 b에 요소를 추가하면 세트 ab에 모두 반영된다.


>>> b.add(5)

>>> a
{1, 2, 3, 4, 5}
>>> b
{1, 2, 3, 4, 5}


  • 세트 ab를 완전히 두 개로 만들려면 copy 메서드로 모든 요소를 복사해야 한다.


>>> a = {1, 2, 3, 4}

>>> b = a.copy()


  • 이제 abis 연산자로 비교해 보면 False가 나오며, 이는 두 세트가 다른 객체라는 것을 의미한다.
  • 하지만 복사한 요소는 같으므로 ==로 비교하면 True가 나온다.


>>> a is b
False

>>> a == b
True


  • 세트 ab는 별개이므로 한쪽의 값을 변경해도 다른 세트에 영향을 미치지 않는다.


>>> a = {1, 2, 3, 4}

>>> b = a.copy()

>>> b.add(5)

>>> a
{1, 2, 3, 4}
>>> b
{1, 2, 3, 4, 5}


7. 반복문으로 세트의 요소를 모두 출력하기

  • 이번에는 세트와 for 반복문을 사용하여 요소를 출력해 보자.


for 변수 in 세트:
    반복할코드


  • 다음은 for로 세트 a의 요소를 출력한다.


>>> a = {1, 2, 3, 4}

>>> for i in a:
...     print(i)
...
1
2
3
4


  • for i in a:는 세트 a에서 요소를 꺼내서 i에 저장하고, 꺼낼 때마다 코드를 반복한다.
  • 단, 세트의 요소는 순서가 없으므로 출력할 때마다 순서가 달라진다.


  • 물론 in 다음에 세트를 직접 지정해도 상관없다.


for i in {1, 2, 3, 4}:
    print(i)


8. 세트 표현식 사용하기

  • 다음과 같이 세트 안에 식과 for 반복문을 지정하면 된다.


{ for 변수 in 반복가능한객체}
set( for 변수 in 반복가능한객체)
>>> a = {i for i in "apple"}

>>> a
{'l', 'p', 'e', 'a'}


  • {} 또는 set() 안에 식, for 변수, in, 반복 가능한 객체를 지정하여 세트를 생성한다.


009


1) 세트 표현식에 if 조건문 사용하기

  • 다음과 같이 if 조건문은 for 반복문 뒤에 지정한다.


{ for 변수 in 세트 if 조건식}
set( for 변수 in 세트 if 조건식)
>>> a = {i for i in "pineapple" if i not in "apl"}

>>> a
{'e', 'i', 'n'}


  • {i for i in "pineapple" if i not in "apl"}은 문자열 "pineapple"에서 "a", "p", "l"을 제외한 문자들로 세트를 생성한다.


010


  • if i not in "apl"{i for i in "pineapple" if i != "a" and i != "p" and i != "l"}과 같이 문자를 하나씩 비교하고 and로 연결하는 if 조건문과 같다.

References