10. 파이썬 집합 자료형

집합의 주요 연산 비교 — 중복을 허용하지 않는 집합 자료형의 3대 연산 특징이다.

이 문서에서는 파이썬의 집합(set) 자료형을 직접 만들어 보고, 중복된 값을 걸러 내는 프로그램 한 개를 완성합니다. 파이썬을 컴퓨터에 설치해 두었고 화면에 글자를 출력하는 print()를 한 번이라도 써 본 상태를 전제로 합니다. 끝까지 따라 하면 set_basic.py 파일 한 개와 set_메모.txt 파일 한 개가 컴퓨터에 남고, 값 여러 개에서 중복을 걸러 내는 코드를 스스로 쓸 수 있습니다.

10.1 – 실습 환경 만들기

집합을 다루기 전에 코드를 쓰고 실행할 자리를 먼저 만듭니다. 여기서는 파이썬을 설치할 때 함께 깔리는 편집기인 IDLE을 씁니다. IDLE(파이썬을 설치하면 함께 설치되는 기본 편집기)은 따로 내려받을 것이 없어 처음 배울 때 준비가 가장 적습니다.

10.1.1 – 작업 환경 준비

파이썬이 실제로 깔려 있는지 먼저 확인합니다. 설치되지 않은 상태에서 코드를 쓰면 실행 단계에서 막히므로, 코드를 쓰기 전에 확인하는 편이 낫습니다.

  1. Windows에서는 키보드의 Windows 키를 누릅니다. macOS에서는 +Space를 누릅니다.
  2. 검색창에 Windows는 cmd, macOS는 터미널을 입력합니다.
  3. Enter 키를 누릅니다. 검은 바탕이나 흰 바탕의 명령 입력 창이 열립니다.
  4. 창 안에 아래 명령을 입력합니다. Windows는 python --version, macOS는 python3 --version을 입력합니다.
  5. Enter 키를 누릅니다.

Python 3.12.1처럼 Python 3으로 시작하는 글자가 나타나면 설치된 상태입니다. 뒤의 숫자는 설치한 버전이라 사람마다 다릅니다.

'python'은(는) 내부 또는 외부 명령... 이 아닙니다command not found가 나타나면 파이썬이 설치되지 않은 상태입니다. https://www.python.org/downloads/에서 설치 파일을 내려받아 설치한 다음, Windows 설치 화면 맨 아래의 Add python.exe to PATH 체크 상자를 켜고 진행합니다. 설치를 마치면 명령 입력 창을 닫았다가 다시 열어 4번 단계를 다시 합니다.

10.1.2 – 작업 폴더와 코드 파일 만들기

이제 여기서 만드는 파일을 한곳에 모아 둘 폴더를 만듭니다. 파일이 여기저기 흩어지면 나중에 다시 열 때 찾지 못하므로, 폴더 하나를 정해 두고 그 안에서만 작업합니다.

  1. Windows는 Windows+E를 눌러 파일 탐색기를 엽니다. macOS는 Finder를 클릭해 엽니다.
  2. 왼쪽 목록에서 문서 폴더를 클릭합니다.
  3. 빈 공간에서 마우스 오른쪽 버튼을 클릭합니다.
  4. 새로 만들기폴더를 클릭합니다. macOS는 새로운 폴더를 클릭합니다.
  5. 폴더 이름 자리에 "파이썬기초"를 입력하고 Enter 키를 누릅니다.

폴더를 만들었으면 그 안에 코드를 쓸 파일을 만듭니다.

  1. Windows는 Windows 키를 누른 뒤 검색창에 IDLE을 입력하고 Enter 키를 누릅니다. macOS는 +Space를 누른 뒤 IDLE을 입력하고 Enter 키를 누릅니다.
  2. IDLE Shell이라는 창이 열립니다. 이 창 위쪽 메뉴에서 FileNew File을 클릭합니다.
  3. 글자를 쓸 수 있는 빈 창이 새로 열립니다.
  4. 빈 창에서 Ctrl+S를 누릅니다. macOS는 +S를 누릅니다.
  5. 저장 창이 열리면 앞에서 만든 "문서/파이썬기초" 폴더로 이동합니다.
  6. 파일 이름 자리에 "set_basic.py"를 입력하고 [저장] 버튼을 클릭합니다.

빈 창의 제목 표시줄이 set_basic.py로 바뀝니다. 앞으로 쓰는 코드는 모두 이 창에 넣고, 실행할 때마다 이 파일에 저장합니다.

IDLE에는 창이 두 가지 있습니다. 처음 열린 IDLE Shell 창은 실행 결과가 나타나는 자리이고, FileNew File로 연 창은 코드를 쓰는 자리입니다. 코드는 언제나 set_basic.py 창에 씁니다.

10.1.3 – 메모 파일 만들기

배운 것을 적어 둘 메모 파일도 함께 만듭니다. 코드만 남기면 몇 주 뒤에 다시 열었을 때 그 코드를 왜 그렇게 썼는지 알기 어렵습니다.

  1. "문서/파이썬기초" 폴더의 빈 공간에서 마우스 오른쪽 버튼을 클릭합니다.
  2. 새로 만들기텍스트 문서를 클릭합니다. macOS는 텍스트 편집기를 열어 새 문서를 만듭니다.
  3. 파일 이름을 "set_메모.txt"로 입력하고 Enter 키를 누릅니다.
  4. 파일을 두 번 클릭해 엽니다. 이 창은 닫지 않고 열어 둡니다.

앞으로 새 명령을 배울 때마다 이 파일에 명령 이름과 하는 일을 한 줄씩 적습니다.

10.2 – 집합 만들기

집합(set)은 중복 없는 값을 순서 없이 모아 두는 자료형입니다. 같은 값을 두 번 넣어도 한 개만 남고, 넣은 순서는 지켜지지 않습니다. 값을 두 번 담지 않는 주머니와 같습니다. 주머니에 같은 사탕을 두 번 넣어도 안에는 한 개만 남는 셈입니다.

비교 대상인 리스트(list)는 값을 넣은 순서대로 모아 두는 자료형입니다. 리스트는 같은 값을 여러 번 담을 수 있고 순서도 그대로 남습니다. 이 차이가 집합을 쓰는 이유입니다.

10.2.1 – 첫 집합 만들고 출력하기

집합을 화면에 찍어 봅니다. 여기서 중복이 실제로 사라지는지 눈으로 확인합니다.

set_basic.py 창을 클릭한 다음 아래 코드를 그대로 입력합니다.

fruits = {"사과", "바나나", "사과", "포도"}
print(fruits)
print(len(fruits))

입력을 마쳤으면 저장하고 실행합니다.

  1. Ctrl+S를 눌러 저장합니다. macOS는 +S를 누릅니다.
  2. F5 키를 눌러 실행합니다.
  3. IDLE Shell 창이 앞으로 나오면서 결과가 나타납니다.

결과는 아래와 비슷하게 나타납니다.

{'포도', '바나나', '사과'}
3

값을 네 개 넣었는데 세 개만 남았습니다. "사과"를 두 번 적었지만 집합은 같은 값을 한 개만 담기 때문입니다. len()은 값이 몇 개 들어 있는지 세는 명령이고, 여기서는 3을 돌려줍니다.

중괄호 {} 안에 값을 쉼표로 나열하면 집합이 만들어집니다. 리스트가 대괄호 []를 쓰는 것과 구분되는 지점입니다.

실행할 때마다 {'사과', '포도', '바나나'}처럼 순서가 달라집니다. 집합은 순서를 지키지 않는 자료형이라, 화면에 나오는 차례가 실행마다 바뀝니다. 순서가 다르게 나와도 잘못된 것이 아닙니다.

10.2.2 – 리스트의 중복을 걸러 내기

집합을 실제로 가장 많이 쓰는 자리는 중복 제거입니다. 값이 여러 번 들어 있는 리스트를 집합으로 바꾸면 중복이 한 번에 사라집니다.

set_basic.py 창의 코드 맨 아래에 아래 세 줄을 이어서 입력합니다.

nums = [1, 2, 2, 3, 3, 3]
unique = set(nums)
print(unique)

Ctrl+S로 저장한 다음 F5 키를 눌러 실행합니다.

IDLE Shell 창 마지막 줄에 {1, 2, 3}이 나타납니다. 리스트 nums에는 값이 여섯 개 있지만, 중복을 뺀 값은 세 개뿐입니다.

set()은 리스트 같은 다른 자료형을 집합으로 바꾸는 명령입니다. 괄호 안에 리스트 이름을 넣으면 그 리스트의 값을 하나씩 집합에 담고, 이미 있는 값은 넣지 않습니다.

원래 리스트 nums는 그대로 남아 있습니다. set()은 새 집합을 만들어 돌려줄 뿐, 넣어 준 리스트를 바꾸지 않기 때문입니다.

10.2.3 – 빈 집합 만들기

값이 하나도 없는 집합을 만들 때는 표기를 조심해야 합니다. 여기서 초보자가 가장 자주 걸리는 함정이 나옵니다.

코드 맨 아래에 아래 세 줄을 이어서 입력합니다.

empty_set = set()
empty_dict = {}
print(type(empty_set), type(empty_dict))

Ctrl+S로 저장한 다음 F5 키를 눌러 실행합니다.

마지막 줄에 <class 'set'> <class 'dict'>가 나타납니다. type()은 값이 어떤 자료형인지 알려 주는 명령입니다.

같은 중괄호를 썼는데 결과가 갈립니다. 빈 중괄호 {}는 집합이 아니라 딕셔너리(키와 값을 짝지어 담는 자료형)로 만들어집니다. 그래서 빈 집합을 만들 때는 반드시 set()이라고 적습니다.

data = {}로 만든 뒤 data.add(1)을 실행하면 AttributeError: 'dict' object has no attribute 'add' 오류가 납니다. 딕셔너리에는 add 명령이 없기 때문입니다. 빈 집합이 필요하면 set()으로 만듭니다.

10.2.4 – 값 넣고 빼기

만들어 둔 집합에 값을 넣거나 빼 봅니다. 프로그램을 돌리는 도중에 값이 바뀌는 상황을 다루기 위해서입니다.

코드 맨 아래에 아래 다섯 줄을 이어서 입력합니다.

box = {1, 2, 3}
box.add(4)
box.add(2)
box.discard(1)
print(box)

Ctrl+S로 저장한 다음 F5 키를 눌러 실행합니다.

마지막 줄에 {2, 3, 4}가 나타납니다. 4는 새로 들어갔고, 1은 빠졌으며, 2는 이미 있던 값이라 다시 넣어도 한 개 그대로입니다.

add()는 집합에 값 하나를 넣습니다. 이미 있는 값을 넣으면 아무 일도 일어나지 않습니다.

discard()는 집합에서 값 하나를 지우고, 없는 값이면 그대로 넘어갑니다. 짝을 이루는 remove()는 집합에서 값 하나를 지우고, 없는 값이면 KeyError 오류를 냅니다.

지울 값이 확실히 있는지 알 수 없을 때는 discard()를 씁니다. 값이 없다는 사실 자체를 오류로 잡아내고 싶을 때만 remove()를 씁니다.

이제 set_메모.txt 창을 클릭해 아래 네 줄을 적어 둡니다.

set() - 리스트 같은 다른 자료형을 집합으로 바꾼다
add(값) - 값 하나를 넣는다. 이미 있으면 그대로 둔다
discard(값) - 값 하나를 지운다. 없으면 그냥 넘어간다
remove(값) - 값 하나를 지운다. 없으면 오류가 난다

10.3 – 집합끼리 견주기

집합 두 개를 놓고 겹치는 값과 한쪽에만 있는 값을 골라냅니다. 앞에서는 집합 한 개를 다뤘고, 여기서는 두 개를 견주는 명령을 씁니다. 두 명단을 놓고 겹치는 사람과 한쪽에만 있는 사람을 가려내는 일과 같은 계산입니다.

10.3.1 – 합집합, 교집합, 차집합

네 가지 기호로 집합 두 개를 견줍니다. 먼저 코드를 실행해 결과를 본 다음 각 기호의 뜻을 확인합니다.

코드 맨 아래에 아래 일곱 줄을 이어서 입력합니다.

a = {1, 2, 3, 4}
b = {3, 4, 5}
print(a | b)
print(a & b)
print(a - b)
print(b - a)
print(a ^ b)

Ctrl+S로 저장한 다음 F5 키를 눌러 실행합니다.

결과는 아래처럼 다섯 줄이 나타납니다.

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

각 줄이 나온 이유는 다음과 같습니다.

  1. a | b는 합집합입니다. 두 집합에 있는 값을 모두 모으고 겹치는 값은 한 개만 남깁니다.
  2. a & b는 교집합입니다. 두 집합 모두에 있는 값만 남깁니다. 34가 양쪽에 있습니다.
  3. a - b는 차집합입니다. a에는 있고 b에는 없는 값만 남깁니다.
  4. b - a도 차집합이지만 기준이 바뀝니다. 빼기는 앞뒤를 바꾸면 결과가 달라집니다.
  5. a ^ b는 대칭차집합입니다. 한쪽에만 있는 값만 남기고 양쪽에 다 있는 값은 뺍니다.

기호가 외워지지 않으면 이름으로 쓴 명령을 대신 써도 됩니다. a | ba.union(b), a & ba.intersection(b), a - ba.difference(b)와 같은 결과를 냅니다.

10.3.2 – 값이 들어 있는지 확인하기

집합에 특정 값이 있는지 묻는 방법을 확인합니다. 중복 검사 프로그램을 만들 때 가장 많이 쓰는 명령입니다.

코드 맨 아래에 아래 세 줄을 이어서 입력합니다.

members = {"김지훈", "이서연", "박민수"}
print("이서연" in members)
print("최유진" in members)

Ctrl+S로 저장한 다음 F5 키를 눌러 실행합니다.

TrueFalse가 차례로 나타납니다. in은 값이 그 안에 있으면 True, 없으면 False를 돌려주는 명령입니다.

같은 in 명령을 리스트에도 쓸 수 있습니다. 다만 값이 아주 많아지면 집합 쪽이 훨씬 빨리 답을 냅니다. 리스트는 값을 앞에서부터 하나씩 훑어 보지만, 집합은 값이 놓인 자리를 곧바로 계산해 찾아가기 때문입니다.

10.3.3 – 순서대로 출력하기

집합은 순서를 지키지 않으므로, 결과를 사람이 읽기 좋게 내놓으려면 정렬을 한 번 거쳐야 합니다.

코드 맨 아래에 아래 두 줄을 이어서 입력합니다.

scores = {70, 100, 85, 100, 70}
print(sorted(scores))

Ctrl+S로 저장한 다음 F5 키를 눌러 실행합니다.

[70, 85, 100]이 나타납니다. 중복이 사라진 값이 작은 순서로 늘어섰습니다.

sorted()는 값을 작은 순서로 늘어놓아 리스트로 돌려주는 명령입니다. 결과를 감싼 기호가 중괄호 {}가 아니라 대괄호 []인 이유가 여기에 있습니다. 돌려받은 값은 집합이 아니라 리스트입니다.

10.3.4 – 완성한 코드 확인하기

지금까지 쓴 코드를 처음부터 다시 읽어 봅니다. 아래는 set_basic.py에 들어 있어야 할 내용 전체입니다.

fruits = {"사과", "바나나", "사과", "포도"}
print(fruits)
print(len(fruits))

nums = [1, 2, 2, 3, 3, 3]
unique = set(nums)
print(unique)

empty_set = set()
empty_dict = {}
print(type(empty_set), type(empty_dict))

box = {1, 2, 3}
box.add(4)
box.add(2)
box.discard(1)
print(box)

a = {1, 2, 3, 4}
b = {3, 4, 5}
print(a | b)
print(a & b)
print(a - b)
print(b - a)
print(a ^ b)

members = {"김지훈", "이서연", "박민수"}
print("이서연" in members)
print("최유진" in members)

scores = {70, 100, 85, 100, 70}
print(sorted(scores))

파일이 이 내용과 같으면 여기까지 마친 상태입니다.

10.3.5 – 직접 만들어 보기

배운 명령을 이어 붙여 프로그램 한 개를 스스로 만듭니다. 아래 조건을 읽고 set_basic.py 맨 아래에 코드를 씁니다.

  1. visitors라는 이름으로 리스트를 만들고 값 "a", "b", "a", "c", "b"를 넣습니다.
  2. 중복을 뺀 방문자를 집합으로 만들어 unique_visitors에 담습니다.
  3. 중복을 뺀 방문자 수를 화면에 출력합니다.
  4. "c"가 방문자 안에 있는지 True 또는 False로 출력합니다.
  5. 방문자를 가나다순으로 늘어놓아 출력합니다.

아래는 정답 예시입니다. 먼저 스스로 써 본 다음 견줘 봅니다.

visitors = ["a", "b", "a", "c", "b"]
unique_visitors = set(visitors)
print(len(unique_visitors))
print("c" in unique_visitors)
print(sorted(unique_visitors))

실행하면 3, True, ['a', 'b', 'c']가 차례로 나타납니다. 값 다섯 개 가운데 서로 다른 값은 세 개이므로 3이 나옵니다.

만든 결과를 아래 기준으로 스스로 따져 봅니다. 세 개 이상 맞으면 이 문서의 내용을 익힌 것으로 봅니다.

  1. set_basic.py 파일이 "문서/파이썬기초" 폴더에 저장돼 있습니다.
  2. F5 키를 눌렀을 때 오류 없이 결과가 끝까지 나타납니다.
  3. 중복된 값이 집합에서 한 개로 줄어드는 것을 코드로 보일 수 있습니다.
  4. 빈 집합을 {}가 아니라 set()으로 만듭니다.
  5. set_메모.txt에 명령 네 개의 하는 일이 적혀 있습니다.

댓글 남기기