1. 세트
■ 세트(set)와 리스트(또는 튜플)의 주요 차이점은 크게 두 가지이다.
■ 첫째, 세트 내 요소는 두 번 나타날 수 없다. 즉, 중복을 허용하지 않는다. 그러므로 세트는 고유한 값들을 저장하는 자료구조라고 할 수 있다.
■ 둘째, 세트 내 요소는 순서를 가지고 있지 않다. 리스트나 튜플과는 다르게 순서가 없으므로 인덱싱이나 슬라이싱이 불가능하고, sort()나 reverse() 같은 리스트 메서드는 세트에서 무의미하다.
cf) 딕셔너리도 순서가 없는 자료형이라서 인덱싱, 슬라이싱을 지원하지 않는다.
cf) 그러므로, 순서가 없는 자료형에 저장된 값을 인덱싱으로 접근하기 위해서는 리스트나 튜플로 변환해야 한다.
1.1 세트를 만드는 방법
■ 파이썬에서 세트를 생성하는 방법은 다음과 같이 {}를 이용하거나 set() 함수를 사용하면 된다.
세트_이름 = {항목1, 항목2, 항목3, ...}
세트_이름 = set()
■ 예를 들어 정수 1, 2, 3을 저장하는 세트를 다음과 같이 {}를 이용해 생성할 수 있다.
num = {1, 2, 3}
■ 비어 있는 세트를 생성하려면 다음과 같이 인수 없는 set() 함수를 사용하면 된다.
num = set()
■ set() 함수를 사용하여 다른 자료형을 세트로 변환하는 것도 가능하다. 아래의 예시는 리스트를 set( ) 함수를 통해 세트로 만드는 예시이다. 이때, 세트는 요소가 중복되면 자동으로 중복된 요소를 제거한다.
list1 = [1, 2, 3, 'a', 'b', 'c', 1, 2, 3, 'a', 'b', 'c', True, False]
set1 = set(list1)
set1
```#결과#```
{1, 2, 3, False, 'a', 'b', 'c'}
````````````
- 불리언 값인 True는 정수 1과 같다고 간주되므로, 세트에서 중복된 요소로 판단되어 제거된 것을 볼 수 있다.
■ set() 함수를 사용하여 문자열로부터 세트를 생성하는 것도 가능하다. 이때, 문자열은 분해되어 문자열의 각 문자들이 하나의 요소가 된다.
s = 'abcd'
set2 = set(s)
set2
```#결과#```
{'a', 'b', 'c', 'd'}
````````````
■ 세트는 세트 안의 요소로 숫자, 문자열, 튜플, 불린값을 가질 수 있지만 리스트나 다른 세트를 요소로 가질 수 없다.
{'a', 'b', [1, 2, 3]}
```#결과#```
TypeError: unhashable type: 'list'
````````````
{'a', 'b', {1, 2}}
```#결과#```
TypeError: unhashable type: 'set'
````````````
1.2 세트 컴프리헨션(Set Comprehensions)
■ 세트도 리스트처럼 컴프리헨션으로 세트를 생성할 수 있다. 단, 세트이기 때문에 세트 내 요소의 중복을 허용하지 않는다.
■ 다음과 같이 리스트 컴프리헨션처럼 필터 조건을 넣거나 조건 수식을 넣어 세트 컴프리헨션을 할 수 있다.
list1 = [1, 2, 3, 4, 5, 4, 3, 2]
result1 = {x for x in list1 if x%2==0}
result1
```#결과#```
{2, 4}
````````````
result2 = {x*x if x%2==0 else 0 for x in list1}
result2
```#결과#```
{0, 4, 16}
````````````
1.3 세트의 연산
■ 세트에 대해서도 all, any, enumerate, len, max, min, sum, sorted 등의 파이썬 내장 함수를 사용할 수 있다.
- all은 세트의 모든 요소가 True인 경우에 True를 반환하고, any는 하나의 요소라도 True이면 True를 반환한다.
print(all(result2))
print(any(result2))
print(len(result2))
print(min(result2))
print(max(result2))
print(sum(result2))
```#결과#```
False
True
3
0
16
20
````````````
■ 세트는 sort를 적용할 수 없지만, sorted 함수를 사용해 정렬된 리스트를 생성할 수 있다.
set3 = {3, 1, 4, 1, 5, 9}
sorted_list1 = sorted(set3)
sorted_list2 = sorted(set3, reverse=True)
print(sorted_list1);print(sorted_list2)
```#결과#```
[1, 3, 4, 5, 9]
[9, 5, 4, 3, 1]
````````````
■ 세트의 요소는 순서가 없기 때문에 인덱스를 이용하여 세트의 요소에 접근할 수 없다. 하지만 다음과 같이 in 연산자나 for 반복문을 이용하여 각 항목들에 접근할 수 있다.
flag = False
if 'a' in set1:
flag = True
print(flag)
```#결과#```
True
````````````
for x in set2:
print(x, end='')
```#결과#```
acbd
````````````
for idx, x in enumerate(set2):
print(idx, x)
```#결과#```
0 a
1 c
2 b
3 d
````````````
1.4 세트의 메서드
1.4.1 add - 값 1개 추가
■ 이미 만들어진 set 자료형에 add() 메서드를 이용하여 하나의 요소를 추가할 수 있다.
set4 = set([1, 2])
set4
```#결과#```
{1, 2}
````````````
set4.add(3)
set4
```#결과#```
{1, 2, 3}
````````````
1.4.2 update - 값 여러 개 추가
■ 여러 개의 요소를 한꺼번에 추가할 때는 update() 메서드를 사용하면 된다.
set4.update(['apple', 'banana', 'grape'])
set4
```#결과#```
{1, 2, 3, 'apple', 'banana', 'grape'}
````````````
■ update() 메서드는 iterable(반복 가능한 객체)만 가능하다. 즉, 리스트나 문자열 튜플만 가능하다.
■ 그래서 위의 예시와 같이 'apple', 'banana', 'grape'가 아닌 ['apple', 'banana', 'grape']로 update하면 set에는 'apple', 'banana', 'grape'가 추가된다. 리스트는 iterable이므로 리스트 내부의 각 요소 즉, 'apple', 'banana', 'grape'가 순서대로 꺼내져서 추가되는 것이다.
■ 만약, 리스트로 감싸지 않고 update를 했다면 리스트가 아닌 문자열을 추가하게 되므로, 문자열은 분해되어 각 문자열의 문자들이 set4에 추가된다.
■ 이러한 이유로 다음과 같이 iterable이 아닌 정수를 update 인자에 넣었을 때 TypeError가 발생하는 것을 확인할 수 있다.
set4.update(1, 2, 3)
```#결과#```
TypeError: 'int' object is not iterable
````````````
1.4.3 remove - 특정 값 제거
■ 특정 요소를 제거할 때는 remove() 메서드를 사용하면 된다.
set4.remove('grape')
set4
```#결과#```
{1, 2, 3, 'apple', 'banana'}
````````````
1.4.4 discard
■ 특정 요소를 제거할 때 discard() 메서드를 사용할 수도 있다.
■ remove() 메서드와의 차이점은, 삭제하고자 하는 요소가 세트 안에 없으면 discard()는 그냥 넘어가지만 remove()는 오류를 생성한다.
set4 = {1, 2, 3, 'apple', 'banana'}
set4.discard(3)
set4
```#결과#```
{1, 2, 'apple', 'banana'}
````````````
set4.discard('2')
set4
```#결과#```
{1, 2, 'apple', 'banana'}
````````````
set4.remove('2')
set4
```#결과#```
KeyError: '2'
````````````
1.4.5 pop
■ 세트의 pop() 메서드는 세트 내의 요소를 랜덤으로 제거하고, 제거하는 값을 반환하는 메서드이다.
set4 = {1, 2, 3, 'apple', 'banana', 'grape'}
set4.pop()
```#결과#```
1
````````````
set4.pop()
```#결과#```
'grape'
````````````
set4.pop()
```#결과#```
3
````````````
1.4.6 clear
■ clear() 메서드는 세트의 모든 요소를 삭제하는 메서드이다. 즉, 공백 세트를 결과로 반환한다.
set4.clear()
set4
```#결과#```
set()
````````````
1.5 부분 집합
■ 파이썬의 세트는 수학의 집합과 같은 것이라서 부분 집합을 생각할 수 있다.
■ 어떤 집합이 다른 집합의 부분 집합인지 확인하는 방법은 < 연산자나 세트의 issubset() 메서드를 사용하면 된다.
■ 진부분 집합(자기 자신을 제외한 부분집합)을 확인하는 방법은 <= 연산자를 사용하면된다.
- 예를 들어 A = {1, 2}라면 부분 집합은 자기 자신인 {1, 2}를 포함한 {}, {1}, {2}, {1, 2}이다.
- 진부분 집합은 여기서 자기 자신을 제외한 나머지 부분집합 모두를 말한다. 그러므로 이 예에서 A의 진부분 집합은 {}, {1}, {2}이다.
A = {'apple', 'banana'}
B = {'apple', 'banana', 'grape', 'orange'}
A < B
```#결과#```
True
````````````
B < A
```#결과#```
False
````````````
A.issubset(A)
```#결과#```
True
````````````
A.issubset(B)
```#결과#```
True
````````````
B <= A
```#결과#```
False
````````````
■ == 연산자와 != 연산자를 사용하여 2개의 세트가 동일한지 검사할 수도 있다.
A == B
```#결과#```
False
````````````
A != B
```#결과#```
True
````````````
1.6 합집합, 교집합, 차집합 연산
■ 세트는 집합 연산(교집합, 합집합, 차집합 연산)을 지원하며, 이것은 연산자나 메서드로 수행할 수 있다.
1.6.1 합집합 연산
■ 합집합은 2개의 집합을 합하는 연산이다. 물론 중복되는 요소는 제외된다.
■ 다음과 같이 | 연산자나 union() 메서드를 사용해서 합집합을 얻을 수 있다.
A = {'apple', 'banana'}
B = {'apple', 'banana', 'grape', 'orange'}
C = {'cat', 'dog', 10}
A.union(B)
```#결과#```
{'apple', 'banana', 'grape', 'orange'}
````````````
A | B
```#결과#```
{'apple', 'banana', 'grape', 'orange'}
````````````
A.union(B).union(C)
```#결과#```
{10, 'apple', 'banana', 'cat', 'dog', 'grape', 'orange'}
````````````
A | B | C
```#결과#```
{10, 'apple', 'banana', 'cat', 'dog', 'grape', 'orange'}
````````````
1.6.2 교집합 연산
■ 교집합은 2개의 집합이 공통으로 포함하는 요소를 구하는 연산이다.
■ 다음과 같이 & 연산자나 intersection() 메서드를 사용해서 교집합을 얻을 수 있다.
A.intersection(B)
```#결과#```
{'apple', 'banana'}
````````````
A & B
```#결과#```
{'apple', 'banana'}
````````````
1.6.3 차집합 연산
■ 차집합은 하나의 집합에서 다른 집합의 요소를 빼는 연산이다.
■ 다음과 같이 - 연산자나 difference() 메서드를 사용해서 차집합을 얻을 수 있다.
A - C
```#결과#```
{'apple', 'banana'}
````````````
B.difference(A)
```#결과#```
{'grape', 'orange'}
````````````
참고) 리스트 <-> 세트
■ 리스트에 set() 함수를 적용하면 세트로 변환된다. 이때 세트는 중복을 허용하지 않으므로, 리스트 내의 요소 중 고유한 요소가 몇 개인지 확인할 수 있다.
list1 = [1, 2, 3, 4, 3, 2, 1]
list2 = [3, 4, 5]
print(len(list1))
print(len(set(list1)))
```#결과#```
7
4
````````````
■ 혹은 서로 다른 리스트의 고유한 항목들에 대해 합집합, 교집합, 차집합 연산을 수행할 수 있다.
set(list1).union(set(list2))
```#결과#```
{1, 2, 3, 4, 5}
````````````
set(list1).intersection(set(list2))
```#결과#```
{3, 4}
````````````
set(list1).difference(set(list2))
```#결과#```
{1, 2}
````````````
2. 딕셔너리
def grade(score):
if score == 10:
return 'D'
elif score == 20:
return 'C'
elif score == 30:
return 'B'
elif score == 40:
return 'A'
■ 위의 함수는 점수를 입력받아 학점을 반환하는 함수로, 이러한 유형의 함수를 '매핑(mapping)'이라고 한다.
■ 매핑 용어에서 점수인 10, 20, 30, 40은 '키(key)', 학점인 A, B, C, D는 '값(value)'에 해당한다.
■ 파이썬은 이러한 매핑 기능을 수행할 수 있는 딕셔너리라는 자료구조를 제공한다.
■ 딕셔너리는 10-D, 20-C, 30-B, 40-A처럼 key-value를 한 쌍으로 가지는, key와 value가 대응 관계를 가지는 자료형이다.
■ 딕셔너리는 리스트나 튜플처럼 시퀀스 자료형이 아니기 때문에, 순차적으로(인덱스를 이용하) 요소에 접근하는 방식이 아니라, key를 통해 key와 대응되는 value를 반환하는 방식으로 동작한다.
2.1 딕셔너리를 만드는 방법
■ 딕셔너리를 만드는 방법은 중괄호 {} 안에 "key : value" 쌍을 쉼표로 구분하여 나열하면 된다. 또는 dict() 함수를 사용하여 공백 딕셔너리를 생성할 수도 있다.
딕셔너리_이름 = {key1: value1, key2: value2, key3: value3, ...}
dict1 = {10: 'D', 20: 'C', 30: 'B', 40: 'A'}
dict2 = dict()
■ 이때, key는 고유한 값을 가지면서 변경할 수 없는 숫자, 문자열, 튜플과 같은 불변 객체만 가능하며, value는 모든 데이터 유형을 가질 수 있다.
■ 즉, key는 반드시 불변 객체이면서 유일해야 하지만, value는 무방하다.
■ 딕셔너리는 해시 테이블(hash table)의 대표적인 예이다. 해시 테이블은 key, value로 데이터를 저장하는 자료구조로, key를 해시값으로 매핑하고, 해시값을 인덱스 혹은 주소로 삼아 데이터의 value를 key와 함께저장한다.
■ 해시 테이블인 딕셔너리는 key로 들어온 값을 해시 함수에 넣어서 계산된 해시값을 사용하여 매핑된 key를 찾는데, 아래 그림처럼 key값이 변경되면 value가 저장된 위치는 그대로 있어도, 해시값이 달라져서 더이상 그 값이 어디에 위치했는지 찾을 수 없게 된다.

■ 이러한 문제를 원천적으로 방지하기 위해 내용이 변하지 않는 변경 불가능한 객체로만 키로 허용하는 것이다.
■ 동일한 key를 추가하면 다음과 같이 나중에 추가된 key와 value에 기존의 key와 value이 덮어씌워지는 문제가 발생한다. 그러므로 key 값은 고유해야 한다.
{'a': 1, 'b': 2, 'a': 3}
```#결과#```
{'a': 3, 'b': 2}
````````````
■ 이러한 원칙 때문에 value로 딕셔너리를 갖는 딕셔너리를 생성할 수 있다.
nations = {
'Canada':{'cont':'North America', 'area':385000},
'France':{'cont':'Europe', 'area':211000}
}
nations
```#결과#```
{'Canada': {'cont': 'North America', 'area': 385000},
'France': {'cont': 'Europe', 'area': 211000}}
````````````
■ 2단계로 중첩된 딕셔너리이므로 예를 들어, 캐나다의 면적에 대한 값을 접근하고 싶은 경우 다음과 같이 상위 key인 'Canada'와 하위 key인 'area'를 지정하면 된다.
nations['Canada']['area']
```#결과#```
385000
````````````
2.2 딕셔너리의 연산
■ value에 접근하는 방법은 다음과 같이 딕셔너리에 key를 입력하면 된다.
dict1[10]
```#결과#```
'D'
````````````
■ key에 대응되는 value를 변경하는 방법은 다음과 같다. 이때, 아래와 같은 구조에서 딕셔너리에 해당 key가 없으면 key : value를 딕셔너리에 추가하게 된다.
dict1 = {10: 'D', 20: 'C', 30: 'B', 40: 'A'}
dict1[10] = 'F'
dict1
```#결과#```
{10: 'F', 20: 'C', 30: 'B', 40: 'A'}
````````````
dict1[50] = 'A+'
dict1
```#결과#```
{10: 'F', 20: 'C', 30: 'B', 40: 'A', 50: 'A+'}
````````````
■ 딕셔너리의 요소를 삭제하는 방법으로 del을 사용하는 방법이 있다. del 딕셔너리_이름[key]를 입력하면 입력한 key에 해당하는 key:value 쌍이 삭제된다.
del dict1[10]
dict1
```#결과#```
{20: 'C', 30: 'B', 40: 'A', 50: 'A+'}
````````````
■ 딕셔너리의 value가 숫자(정수, 부동소수점)인 경우, 다음과 같이 복합 대입 연산자를 이용하여 value의 값을 수정할 수 있다.
dict1 = {'apple': 10, 'grape': 20, 'banana': 30, 20: 'C', 30: 'B'}
dict1['apple'] += 1
dict1['grape'] /= 2
dict1
```#결과#```
{'apple': 11, 'grape': 10.0, 'banana': 30, 20: 'C', 30: 'B'}
````````````
dict2 = {'apple': 0.3, 20: 'C', 30: 'B'}
dict2['apple'] += 1
dict2
```#결과#```
{'apple': 1.3, 20: 'C', 30: 'B'}
````````````
2.3 딕셔너리의 메서드
2.3.1 keys - 딕셔너리 내 키(key) 반환
■ keys() 메서드는 딕셔너리의 key 값들만 모아 dict_keys 라는 객체를 반환하는 함수이다.
dict1.keys()
```#결과#```
dict_keys([20, 30, 40, 50])
````````````
2.3.2 values - 딕셔너리 내 값(value) 반환
■ values() 메서드는 딕셔너리의 value 값들만 모아 dict_values라는 객체를 반환하는 함수이다.
dict1.values()
```#결과#```
dict_values(['C', 'B', 'A', 'A+'])
````````````
2.3.3 items - [ (key, value) ] 반환
■ items() 메서드는 딕셔너리 안의 모든 key-value를 튜플로 묶은 (key, value) 값을 dict_items 객체로 반환하는 메서드이다.
dict1.items()
```#결과#```
dict_items([(20, 'C'), (30, 'B'), (40, 'A'), (50, 'A+')])
````````````
2.3.4 get
■ get() 메서드는 지정된 key에 대응되는 value를 반환하는 함수이다.
■ 딕셔너리_이름.get('key') 형태로 지정된 key에 대응되는 value를 반환하는데, 딕셔너리에 해당 key가 없다면 None을 반환한다.
dict1.get(20)
```#결과#```
'C'
````````````
print(dict1.get('20'))
```#결과#```
None
````````````
- 딕셔너리_이름['key'] 방식은 딕셔너리에 해당 key가 없다면 오류를 발생시킨다.
2.3.5 pop, popitem
■ 딕셔너리의 특정 요소를 삭제할 때 pop() 메서드, popitem() 메서드를 사용한다.
■ pop() 메서드는 다음과 같이 지정된 key에 대응되는 value를 반환하고, 해당 key-value 쌍을 딕셔너리에서 삭제한다.
dict1.pop(20)
```#결과#```
'C'
````````````
dict1
```#결과#```
{30: 'B', 40: 'A', 50: 'A+'}
````````````
■ popitem() 메서드는 "마지막으로 추가된 key-value 쌍을 삭제"하고, 삭제한 key-value 쌍을 반환하는 메서드이다.
dict1.popitem()
```#결과#```
(50, 'A+')
````````````
dict1
```#결과#```
{30: 'B', 40: 'A'}
````````````
2.3.6 clear
■ clear() 메서드는 딕셔너리 내의 모든 요소를 삭제하는 메서드이다.
dict1.clear()
dict1
```#결과#```
{}
````````````
2.3.7 update
■ update() 메서드를 이용해서 기존 딕셔너리에 새로운 key-value 쌍을 추가하거나 기존의 value를 수정할 수 있다.
dict1.update({'apple':10})
dict1
```#결과#```
{'apple': 10}
````````````
dict1.update({'grape':20, 'banana':30})
dict1
```#결과#```
{'apple': 10, 'grape': 20, 'banana': 30}
````````````
dict1.update({'apple':100})
dict1
```#결과#```
{'apple': 100, 'grape': 20, 'banana': 30}
````````````
■ 또한, 딕셔너리를 병합할 수 있다.
dict1 = {'apple': 100, 'grape': 20, 'banana': 30}
dict2 = {'apple': 10, 20: 'C', 30: 'B'}
dict1.update(dict2)
■ 이때, 두 딕셔너리가 동일한 key를 가진다면, dict1의 value를 dict2의 value로 대체한다.
dict1
```#결과#```
{'apple': 10, 'grape': 20, 'banana': 30, 20: 'C', 30: 'B'}
````````````
2.4 딕셔너리 컴프리헨션
■ 딕셔너리도 컴프리헨션이 가능하다. 단, 다른 자료형의 컴프리헨션과 다른 점은 출력 수식으로 key:value 쌍을 지정해야 한다는 점이다.
■ 아래 예시 코드는 딕셔너리 컴프리헨션을 이용하여, 리스트에서 값을 하나씩 꺼낸 뒤 짝수인 경우에만 x: x*x 형태의 key: value 쌍으로 구성된 딕셔너리를 생성하는 코드이다.
list1 = [1, 2, 3, 4, 5]
dict1 = {x:x*x for x in list1 if x%2==0}
dict1
```#결과#```
{2: 4, 4: 16}
````````````
'파이썬' 카테고리의 다른 글
제어문(control statement) (2) - 반복문 for, while (0) | 2024.09.02 |
---|---|
제어문(control statement) (1) - 조건문 if (0) | 2024.08.28 |
자료형(Data Type) (3) - 튜플, 불(bool) (0) | 2024.08.23 |
자료형(Data Type) (2) - 리스트 (0) | 2024.08.22 |
자료형(Data Type) (1) - 숫자, 문자열 (2) | 2024.08.21 |