[Python] 11. 자료구조 - Set Dictionary

Wonder_Land🛕·2022년 6월 24일
0

[Python]

목록 보기
11/12
post-thumbnail
  1. Set의 생성 및 조작
  2. Set 내포(Set Comprehension)의 특징
  3. Dictionary의 생성 및 조작
  4. Dictionary 내포(Dictionary Comprehension)의 특징
  5. Q&A
  6. 마치며

우리는 프로그래밍 중 다양한 데이터 중에서
중복되지 않은 유일한 정보가 필요할 때가 있습니다.

예를 들면, 학생의 정보 중에서,
'학번'은 다른 학생과 구별할 수 있는 중요한 식별자입니다.

이러한 식별자는 '키 데이터(Key Data)'라고 하는데,
Key data는 중복되지 않는 유일한 값이어야 합니다.

Python에서는 중복되지 않는 데이터를 위한 자료구조인 셋(Set)
Key Data와 관련된 데이터를 위한 자료구조인 딕셔너리(Dictionary)를 지원합니다.

Set과 Dictionary는 iterable하며, 데이터의 중복을 허용하지 않는다는 특징이 있습니다.


1. Set의 생성 및 조작

  • 셋(Set)
    : {} 안에 서로 다른 자료형의 값,로 구분해 하나 이상 저장할 수 있는 컬렉션 자료형
  • index를 제공하지 않습니다.

  • 순서의 개념이 없습니다. (Sequence type이 아닙니다.)

  • 각 element의 중복을 허용하지 않습니다.

1) Set의 생성

Set = {10, 21.5, "파이썬", "파이썬", True}	# 선언 및 생성
print(f"{type(Set)} {Set}")

[Result]
<class 'set'> {True, 10, 21.5, '파이썬'}

각 element의 중복을 허용하지 않아,
문자열 "파이썬"은 한 번만 저장되었습니다.


2) Set의 조작

  1. Set의 기본 연산
  2. Set의 항목 추가
  3. Set의 항목 제거
  4. Set의 항목 확인
  5. Set와 for문 (Set 객체의 개별 항목 접근법)

에 대해 각각 알아보겠습니다.

(1) Set의 기본 연산

각 연산은
1) & | - 연산자를 이용한 방법
2) Set의 내장함수를 이용하는 방법
이 있습니다.

(1.1) 교집합(intersection) &

Set1 = {1, 2, 3, 4, 5, 6, 7, 8}
Set2 = {6, 7, 8}

# 교집합(intersection)
print(f"{Set1} & {Set2} => {Set1 & Set2}")
print(f"Set1.intersection(Set2) => {Set1.intersection(Set2)}")

[Result]
{1, 2, 3, 4, 5, 6, 7, 8} & {8, 6, 7} => {8, 6, 7}
Set1.intersection(Set2) => {8, 6, 7}

(1.2) 합집합(union) |

Set1 = {1, 2, 3, 4, 5, 6, 7, 8}
Set2 = {6, 7, 8}

# 합집합(union)
print(f"{Set1} | {Set2} => {Set1 | Set2}")
print(f"Set1.union(Set2) => {Set1.union(Set2)}")

[Result]
{1, 2, 3, 4, 5, 6, 7, 8} | {8, 6, 7} => {1, 2, 3, 4, 5, 6, 7, 8}
Set1.union(Set2) => {1, 2, 3, 4, 5, 6, 7, 8}

(1.3) 차집합(difference) -

Set1 = {1, 2, 3, 4, 5, 6, 7, 8}
Set2 = {6, 7, 8}

# 차집합(difference)
print(f"{Set1} - {Set2} => {Set1 - Set2}")
print(f"Set1.difference(Set2) => {Set1.difference(Set2)}")

[Result]
{1, 2, 3, 4, 5, 6, 7, 8} - {8, 6, 7} => {1, 2, 3, 4, 5}
Set1.difference(Set2) => {1, 2, 3, 4, 5}

이 때, 각 연산의 결과에서는
각 항목은 중복없이 한 번만 사용됩니다.


(2) Set의 항목 추가

(2.1) add()함수를 이용한 항목 추가

Set의 내장함수 add()함수는,
Set의 마지막에 항목을 추가합니다.

반환값은 None으로 없습니다.

Set = {1, 2, 3}

Set.add(3)  # 마지막에 '3' 추가 (중복)
Set.add(4)  # 마지막에 '4' 추가
print(f"Set : {Set}")

[Result]
Set : {1, 2, 3, 4}

결과에서 알 수 있듯이,
중복된 값을 추가하게 되면 추가하지 않습니다.

(2.2) update()함수를 이용한 항목 추가

Set의 내장함수 update()함수는,
Set의 마지막에 여러 항목을 추가합니다.

Set = {1, 2, 3}
Set.update({3, 4, 5})  # 마지막에 '3(중복), 4, 5' 추가

print(f"Set : {Set}")

[Result]
Set : {1, 2, 3, 4, 5}


(3) Set의 항목 제거

(3.1) remove()함수를 이용한 제거

Set의 내장함수인 remove()함수는,
특정 값을 가지는 항목을 제거합니다.

Set = {1, 2, 3, 4, 5}
Set.remove(3)  # '3' 제거

print(f"Set : {Set}")

[Result]
Set : {1, 2, 4, 5}

(3.2) pop()함수를 이용한 제거

Set의 내장함수인 pop()함수는,
Set의 첫 번째 항목을 제거합니다.

Set = {1, 2, 3, 4, 5}
Set.pop()  # 첫 번째 항목 제거

print(f"Set : {Set}")

[Result]
Set : {2, 3, 4, 5}

(3.3) clear()함수를 이용한 제거

Set의 내장함수인 clear()함수는,
해당 Set의 모든 항목을 제거합니다.

Set = {1, 2, 3, 4, 5}
Set.clear()  # 모든 항목 제거

print(f"Set : {Set}")

[Result]
Set : set()

이 때, 비어있는 set은 set()이라고 표현하는데,
{}는 Dictionary 리터럴이기 때문에,
비어있는 set은 set()이라고 표현합니다.
(만약 set도 {}라고 표현하면, Dictionary와 헷갈리겠죠? 😉)


(4) Set의 항목 확인

(4.1) in 명령어를 통한 확인

in 명령어는,
Set 객체에 해당 항목이 있는지 확인합니다.

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

print(f"3 in Set => {3 in Set}")

[Result]
3 in Set => True

반대로 없는지 검사하려면, not in명령어를 사용할 수 있습니다.

(4.2) issuperset() issubset() 함수를 통한 부분집합의 확인

issuperset() 함수는,
다른 집합을 포함하는지를 확인합니다.

issubset() 함수는,
다른 집합에 포함되는지를 확인합니다.

Set1 = {1, 2, 3, 4, 5}
Set2 = {2, 3, 4}

print(f"Set1.issuperset(Set2) => {Set1.issuperset(Set2)}")
print(f"Set2.issubset(Set1) => {Set2.issubset(Set1)}")

[Result]
Set1.issuperset(Set2) => True
Set2.issubset(Set1) => True


(5) Set와 for문 (Set 객체의 개별 항목 접근법)

Set = set(range(0, 11, 2))

for i in Set:
    print(i, end = " ")

print()

for idx, val in enumerate(Set):
    print(f"Set[{idx}] => {val}")

[Result]
0 2 4 6 8 10
Set[0] => 0
Set[1] => 2
Set[2] => 4
Set[3] => 6
Set[4] => 8
Set[5] => 10

for i in Set:를 통해,
Set의 항목을 반복해서 변수 i에 저장합니다.

for idx, val in enumerate(Set):를 통해,
Set을 enumerateion 객체로 변환하고
index와 값을 반복해서 변수 idx, val에 저장합니다.


2. Set 내포(Set Comprehension)의 특징

1) Set의 내포(Set Comprehension)

  • Set의 내포(Set Comprehension)
    : Set의 선언 및 초기화 시 for문과 if문을 한 라인에 작성하는 방법
() = [(표현식) for (변수) in (iterable 객체)]
() = [(표현식) for (변수) in (iterable 객체) if (조건식)]


코드를 직관적이고, 실행 속도를 빠르게 해주는 장점이 있습니다.

iterable 자료형(List, Tuple, str, ...)의 경우,
리터럴 안에서 for문을 사용하면 내포 기능을 사용 할 수 있습니다.

Set 내포(Set Comprehesion)를 사용해 볼까요?

Set1 = {1, 2, 3, 4, 5}
print(f"Set1 : {Set1}")

Set2 = {i for i in Set1}	# Set Comprehension
print(f"Set2 : {Set2}")

[Result]
Set1 : {1, 2, 3, 4, 5}
Set2 : {1, 2, 3, 4, 5}

Set2 = {i for i in Set1}를 통해,
Set1을 반복해서 참조하는 변수 i의 값으로 이루어진 Set2를 만들게 됩니다.


2) Set 내포의 조건문

Set 내포 기능을 사용할 때, 조건을 추가할 수도 있습니다.

아래의 예시는, for문과 if문을 통해 값을 Set2에 전달하고 있습니다.

Set 내포(Set Comprehesion)를 사용해 볼까요?

Set1 = {1, 2, 3, 4, 5}
print(f"Set1 : {Set1}")

Set2 = {i for i in Set1 if i % 2 == 1}	# Set Comprehension with condition
print(f"Set2 : {Set2}")

[Result]
Set1 : {1, 2, 3, 4, 5}
Set2 : {1, 3, 5}


3) Set 내포의 중첩

Set 내포 기능을 사용할 때, 중첩해서도 사용할 수 있습니다.

Set 내포(Set Comprehesion)를 사용해 볼까요?

Set1 = {1, 2, 3, 4}

# 중첩 Set Comprehension with condition
Set2 = {i * j for i in Set1 if i % 2 == 1
              for j in Set1 if j % 2 == 0}

print(f"Set2 : {Set2}")

[Result]
Set2 : {2, 4, 6, 12}

이처럼 Set 내포(Set Comprehension)를 사용하면,
for / if문보다 직관적이고, 짧고, 간결하며, 더 빠른 코드를 작성할 수 있습니다.

자주 등장하고 사용할 기능이니 꼭 알고 계셔야 합니다 😊


3. Dictionary의 생성 및 조작

  • 딕셔너리(Dictionary)
    : {} 안에 key:value 형식을 가진 유일한 데이터,로 구분해 하나 이상 저장할 수 있는 컬렉션 자료형
  • index를 제공하지 않습니다.

  • 순서의 개념이 없습니다. (Sequence type이 아닙니다.)

  • 각 element의 중복을 허용하지 않습니다.

(Set과 비슷하죠? 😊)

1) Dictionary의 생성

(1) {key:value} 형식의 생성

dct = {    # 선언 및 생성
    "A" : 1,
    "B" : 2,
    "C" : 3
}
print(f"{type(dct)} {dct}")

[Result]
<class 'dict'> {'A': 1, 'B': 2, 'C': 3}

(2) 매개변수 목록을 이용한 생성

매개변수 목록을 기술해 Dictionary 객체를 생성할 수도 있습니다.

(딕셔너리) = dict(key = value, ...)

dct = dict(A = 1, B = 2, C = 3)   # 선언 및 생성
print(f"{type(dct)} {dct}")

[Result]
<class 'dict'> {'A': 1, 'B': 2, 'C': 3}

이 때, key문자열로 작성하지 않도록 주의해야 합니다.

(3) Tuple로 이루어진 Tuple, List, Set의 변환

tpl = (("A", 1), ("B", 2), ("C", 3)) # Tuple with tuple
lst = [("A", 1), ("B", 2), ("C", 3)] # List with tuple
Set = {("A", 1), ("B", 2), ("C", 3)} # Set with tuple

print(f"tpl : {type(tpl)} {tpl}")
print(f"lst :  {type(lst)} {lst}")
print(f"Set :   {type(Set)} {Set}")

[Result]
tpl : <class 'tuple'> (('A', 1), ('B', 2), ('C', 3))
lst : <class 'list'> [('A', 1), ('B', 2), ('C', 3)]
Set : <class 'set'> {('A', 1), ('B', 2), ('C', 3)}


2) Dictionary의 조작

  1. Dictionary의 항목 접근
  2. Dictionary의 항목 추가
  3. Dictionary의 항목 변경
  4. Dictionary의 항목 제거
  5. Dictionary의 항목 확인
  6. Dictionary와 for문 (Dictionary 객체의 개별 항목 접근법)

에 대해 각각 알아보겠습니다.

(1) Dictionary 의 항목 접근

(1.1) key를 이용한 접근

각 항목은 key를 이용해 접근 할 수 있습니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

print(f"dct[\"A\"] => {dct['A']}")

[Result]
dct["A"] => 1

(1.2) KeyError

만약, 유효한 Key가 아니라면, KeyError가 발생하니 주의해 주세요!

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

print(f"dct[\"Z\"] => {dct['Z']}")

[Result]
KeyError: 'Z'


(2) Dictionary의 항목 추가

(2.1) 중복되지 않은 Key를 이용한 항목 추가

Dictionary에 중복되지 않은 Key에 값을 저장하면,
항목을 추가 할 수 있습니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

dct["D"] = 4	# 중복되지 않은 Key
print(f"dct : {dct}")

[Result]
dct : {'A': 1, 'B': 2, 'C': 3, 'D': 4}

(2.2) update()함수를 이용한 항목 추가

Dictionary의 내장함수 update()함수는,
Dictionary의 마지막에 여러 항목을 추가합니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

dct.update({"D" : 4, "E" : 5}) # 마지막에 '{"D" : 4, "E" : 5}' 추가
print(f"dct : {dct}")

[Result]
dct : {'A': 1, 'B': 2, 'C': 3, 'D': 4, 'E': 5}


(3) Dictionary의 항목 변경

(3.1) 중복된 Key를 이용한 항목 추가

Dictionary에 중복된 Key에 값을 저장하면,
항목을 변경 할 수 있습니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

dct["C"] = 4	# 중복된 Key
print(f"dct : {dct}")

[Result]
dct : {'A': 1, 'B': 2, 'C': 4}

(3.2) update()함수를 이용한 항목 변경

Dictionary의 내장함수 update()함수는,
Dictionary의 동일한 Key의 값을 변경합니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

dct.update({"B" : 4, "C" : 5}) # 중복된 Key
print(f"dct : {dct}")

[Result]
dct : {'A': 1, 'B': 4, 'C': 5}


(4) Dictionary의 항목 제거

(4.1) del 명령어를 이용한 제거

del 명령어를 이용하여,
특정 Key의 항목을 제거할 수 있습니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

del dct["C"]	# 특정 Key의 항목 제거
print(f"dct : {dct}")

[Result]
dct : {'A': 1, 'B': 2}

(4.2) pop()함수를 이용한 제거

Dictionary의 내장함수인 pop()함수를 통해,
특정 Key의 항목을 제거할 수 있습니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

dct.pop("C")	# 특정 Key의 항목 제거
print(f"dct : {dct}")

[Result]
dct : {'A': 1, 'B': 2}

(4.3) clear()함수를 이용한 제거

Dictionary의 내장함수인 clear()함수를 통해,
해당 Dictionary의 모든 항목을 제거할 수 있습니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

dct.clear()
print(f"dct : {dct}")

[Result]
dct : {}


(5) Dictionary의 항목 확인

(5.1) in 명령어를 통한 확인

in 명령어는,
Dictionary 객체에 특정 Key에 해당하는 항목이 있는지 확인합니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

print(f"\"A\" in dct => {'A' in dct}")

[Result]
"A" in dct => True

반대로 없는지 검사하려면, not in명령어를 사용할 수 있습니다.


  1. Dictionary와 for문 (Dictionary 객체의 개별 항목 접근법)

(6) Dictionary와 for문 (Dictionary 객체의 개별 항목 접근법)

(6.1) Dictionary 객체 자체를 이용

for문에 Dictionary객체 자체를 이용하면,
Key를 반복해서 변수에 저장합니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

for k in dct:	# dct의 Key가 변수 k에 저장
    print(f"{k} => {dct[k]}")

[Result]
A => 1
B => 2
C => 3

(6.2) keys() 함수를 이용

Dictionary의 내장함수 keys()는,
Key들을 dict_keys 객체로 반환합니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}


for k in dct.keys():    # dict_keys 객체 반환
    print(f"{k} => {dct[k]}")

[Result]
A => 1
B => 2
C => 3

Dictionary의 각각의 Key는
반복할 때마다 변수 k에 저장됩니다.

(6.3) items() 함수를 이용

Dictionary의 내장함수 items()는,
Tuple 타입의 (Key, Value)들로 구성된 dict_items 객체를 반환합니다.

이 때, dict_items객체는 아래의 방법

1) index를 이용
2) Tuple로 이용

으로 이용할 수 있습니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

# 1) index로 이용
for item in dct.items():
    print(f"{item[0]} => {item[1]}")
print()

# 2) Tuple로 이용
for key, value in dct.items():
    print(f"{key} => {value}")

[Result]
A => 1
B => 2
C => 3

A => 1
B => 2
C => 3

(6.4) values() 함수를 이용

Dictionary의 내장함수 values()는,
Value들을 dict_values 객체를 반환합니다.

dct = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}

for val in dct.values():    # dict_values 객체 반환
    print(f"value => {val}")

[Result]
value => 1
value => 2
value => 3

Dictionary의 각각의 Value는
반복할 때마다 변수 val에 저장됩니다.


4. Dictionary 내포(Dictionary Comprehension)의 특징

1) Dictionray의 내포(Dictionray Comprehension)

  • Dictionary의 내포(Dictionary Comprehension)
    : Dictionary의 선언 및 초기화 시 for문과 if문을 한 라인에 작성하는 방법
(딕셔너리) = [(표현식) for (변수) in (iterable 객체)]
(딕셔너리) = [(표현식) for (변수) in (iterable 객체) if (조건식)]


코드를 직관적이고, 실행 속도를 빠르게 해주는 장점이 있습니다.

iterable 자료형(List, Tuple, str, ...)의 경우,
리터럴 안에서 for문을 사용하면 내포 기능을 사용 할 수 있습니다.

Dictionary 내포(Dictionary Comprehesion)를 사용해 볼까요?

(1) items() 함수를 이용한 방법

(1.1) index로 이용

dct1 = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}
print(f"dct1 : {type(dct1)} {dct1}")


dct2 = {item[0] : item[1] for item in dct1.items()}  # Dict Comprehension
print(f"dct2 : {type(dct2)} {dct2}")

[Result]
dct1 : <class 'dict'> {'A': 1, 'B': 2, 'C': 3}
dct2 : <class 'dict'> {'A': 1, 'B': 2, 'C': 3}

dct2 = {item[0] : item[1] for item in dct1.items()}를 통해

item[0]에 저장된 Key와
item[1]에 저장된 Value를

Dictionary 형태dct2에 각각 저장합니다.

(1.2) Tuple로 이용

dct1 = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}
print(f"dct1 : {type(dct1)} {dct1}")

dct2 = {item for item in dct1.items()}	# Dict Comprehension
print(f"dct2 : {type(dct2)} {dct2}")

[Result]
dct1 : <class 'dict'> {'A': 1, 'B': 2, 'C': 3}
dct2 : <class 'set'> {('C', 3), ('A', 1), ('B', 2)}

dct2 = {item for item in dct1.items()}를 통해,

item에 저장된 Key와
각 Key에 해당하는 Value를

Tuple 형태로 각각 저장되어,
dct2set type이 됩니다.


(2) {Key : Value} 형식을 이용한 방법

(2.1) Key로 참조

dct1 = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}
print(f"dct1 : {type(dct1)} {dct1}")

dct2 = {k : dct1[k] for k in dct1}	# Dict Comprehension
print(f"dct2 : {type(dct2)} {dct2}")

[Result]
dct1 : <class 'dict'> {'A': 1, 'B': 2, 'C': 3}
dct2 : <class 'dict'> {'A': 1, 'B': 2, 'C': 3}

dct2 = {k : dct1[k] for k in dct1}를 통해,

변수 k에 저장된 Key와
각 Key에 해당하는 Value를

Dictionary 형태dct2에 각각 저장합니다.

(2.2) Key, Value로 참조

dct1 = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}
print(f"dct1 : {type(dct1)} {dct1}")

dct2 = {k : v for k, v in dct1.items()}	# Dict Comprehension
print(f"dct2 : {type(dct2)} {dct2}")

[Result]
dct1 : <class 'dict'> {'A': 1, 'B': 2, 'C': 3}
dct2 : <class 'dict'> {'A': 1, 'B': 2, 'C': 3}

dct2 = {k : v for k, v in dct1.items()} 통해,
변수 k에 저장된 Key와
변수 v에 저장된 Value를
Dictionary 형태dct2에 각각 저장합니다.

(3) keys() 함수를 이용한 방법

dct1 = {
    "A" : 1,
    "B" : 2,
    "C" : 3
}
print(f"dct1 : {type(dct1)} {dct1}")

dct2 = {k:dct1[k] for k in dct1.keys()}	# Dict Comprehension
print(f"dct2 : {type(dct2)} {dct2}")

[Result]
dct1 : <class 'dict'> {'A': 1, 'B': 2, 'C': 3}
dct2 : <class 'dict'> {'A': 1, 'B': 2, 'C': 3}

dct2 = {k:dct1[k] for k in dct1.keys()}를 통해,
dct1.keys()로 반환된 Key와
각 Key에 해당하는 Value를
Dictionary 형태dct2에 각각 저장합니다.


5. Q&A

-


6. 마치며

오늘은 지난 글에서 등장했던List와 Tuple에 이어서,

SetDictionary를 자세히 살펴봤습니다.

이 두 구조를 다루기 위해서는 list와 tuple에 대한 내용도 알고 있어야합니다.
(개념과 활용에서 상당히 많이 쓰이기 때문이죠)

Iterable한 Type의 대표적인 자료구조인 Set과 Dictionary는 유용하게 쓰일 수 있는 구조입니다.

list, tuple과 다르게
중복을 허용하지 않는 유일성을 보장하기 때문이죠.
따라서 손쉽게 유일성을 가진 데이터를 다룰 수 있습니다.

하지만 Set과 Dictionary는 Seuquence의 개념이 없기 때문에,
이 두 구조에 익숙하지 않은 사람들은 처음에 낯설어할 수도 있겠네요.
(저 같은 경우는, 계속 index로 참조하는 실수를 저지르네요....)
(Sequence의 개념이 없기 때문에, index가 없는데도 말이죠..😢)

그러니 각 자료형의 내장함수 및 활용법을 자세히 알고있는게 좋겠죠?

저번 시간에 배웠던 내용과 이번 시간에 배운 내용을 기억해두면 상당히 유용할 것입니다!!
(실제로 모르고 문제에 접근할 때와 알고 접근할 때 엄청 다르네요..)

그리고 또 다른 내용인 '내포'

Dictionary 같은 경우는 내포를 할 수 있는 방식이 많아 헷갈릴 수 있는데요(사실 제가...ㅎㅎ),
{key:Value}의 형식을 어떻게 표현하느냐의 차이라서,
조금만 익숙해지시면 금방 적응할 것 같습니다 😊

[Reference] : 위 글은 다음 내용을 참고, 인용하여 만들어졌습니다.

  • 전반적 내용 : 삼성 SW Expert Academy
profile
아무것도 모르는 컴공 학생의 Wonder_Land

0개의 댓글