일반적인 Python 데이터 구조(가이드)2

2023. 12. 29. 19:03python/basic

집합과 다중 집합

집합은 중복 요소를 허용하지 않는 순서가 지정되지 않은 개체 컬렉션입니다. 일반적으로 집합은 값이 집합에 속하는지 빠르게 테스트하고, 집합에서 새 값을 삽입 또는 삭제하고, 두 집합의 합집합이나 교집합을 계산하는 데 사용됩니다.

dict와 마찬가지로 집합도 Python에서 특별하게 처리되며 집합을 쉽게 만들 수 있는 몇 가지 구문 설탕이 있습니다. 예를 들어 중괄호 집합 표현식 구문과 집합 이해를 사용하면 새 집합 인스턴스를 편리하게 정의할 수 있습니다.

In [ ]:
vowels = {"a", "e", "i", "o", "u"}
squares = {x * x for x in range(10)}

하지만 주의하세요. 빈 집합을 만들려면 set() 생성자를 호출해야 합니다. 빈 중괄호({})를 사용하면 모호해지며 대신 빈 사전이 생성됩니다.

set: 당신의 이동 집합

set 유형은 Python에 내장된 집합 구현입니다. 이는 변경 가능하며 요소의 동적 삽입 및 삭제를 허용합니다.

In [ ]:
vowels = {"a", "e", "i", "o", "u"}
"e" in vowels
In [ ]:
letters = set("alice")
letters.intersection(vowels)
In [ ]:
vowels.add("x")
vowels
In [ ]:
len(vowels)

frozenset: 불변 세트

frozenset 클래스는 생성된 후에는 변경할 수 없는 set의 불변 버전을 구현합니다.

frozenset 개체는 정적이며 해당 요소에 대한 쿼리 작업만 허용하고 삽입이나 삭제는 허용하지 않습니다. frozenset 객체는 정적이며 해시 가능하므로 사전 키나 다른 세트의 요소로 사용할 수 있습니다.

In [ ]:
vowels = frozenset({"a", "e", "i", "o", "u"})
vowels.add("p")
In [ ]:
# Frozensets은 hashable 이며,
# dictionary keys로 사용될 수 있습니다.:
d = { frozenset({1, 2, 3}): "hello" }
d[frozenset({1, 2, 3})]

collections.Counter: 다중 집합

Python 표준 라이브러리의 collections.Counter 클래스는 집합의 요소가 두 번 이상 발생하도록 허용하는 다중 집합 또는 백 유형을 구현합니다.

In [ ]:
from collections import Counter
inventory = Counter()

loot = {"sword": 1, "bread": 3}
inventory.update(loot)
inventory
In [ ]:
more_loot = {"sword": 1, "apple": 1}
inventory.update(more_loot)
inventory

Counter 클래스에 대한 한 가지 주의 사항은 Counter 개체의 요소 수를 계산할 때 주의해야 한다는 것입니다. len() 호출은 다중 집합의 고유 요소 수를 반환하는 반면, 요소 수의 총합은 sum()을 사용하여 검색할 수 있습니다.

In [ ]:
len(inventory)
In [ ]:
sum(inventory.values())

스택(LIFO)

스택 데이터 구조에 대한 유용한 실제 비유는 접시 스택입니다. 새로운 접시는 더미의 맨 위에 추가되며, 접시는 소중하고 무거우므로 맨 위에 있는 접시만 이동할 수 있습니다. 즉, 스택의 마지막 접시가 제거된 첫 번째 접시여야 합니다(LIFO). 스택에서 아래쪽에 있는 접시에 접근하려면 맨 위에 있는 접시를 하나씩 제거해야 합니다.

list: 간단한 내장 스택

Python의 list은 내부적으로 동적 배열로 구현됩니다. 즉, 요소가 추가되거나 제거될 때 list에 저장된 요소의 저장 공간 크기를 조정해야 하는 경우가 있습니다. list은 모든 푸시 또는 팝에 크기 조정이 필요하지 않도록 백업 스토리지를 과도하게 할당합니다. 결과적으로 이러한 작업에 대해 상각된 O(1) 시간 복잡도를 얻게 됩니다.

In [ ]:
s = []
s.append("eat")
s.append("sleep")
s.append("code")

s
In [ ]:
s.pop()
In [ ]:
s.pop()
In [ ]:
s.pop()
In [ ]:
s.pop()

collections.deque: 빠르고 견고한 스택

deque 클래스는 양쪽 끝에서 요소 추가 및 제거를 지원하는 양단 대기열을 구현합니다. Python의 deque 객체는 이중 연결 목록으로 구현되어 다음에 대한 우수하고 일관된 성능을 제공합니다.

In [ ]:
!pip install collections
In [ ]:
from collections import deque
s = deque()
s.append("eat")
s.append("sleep")
s.append("code")

s
In [ ]:
s.pop()
In [ ]:
s.pop()
In [ ]:
s.pop()
In [ ]:
s.pop()

queue.LifoQueue: 병렬 컴퓨팅을 위한 잠금 의미론

Python 표준 라이브러리의 LifoQueue 스택 구현은 동기화되고 잠금 의미를 제공하여 생산자와 소비자.에게 다중 동시 지원합니다. 사용 사례에 따라 잠금 의미 체계가 도움이 될 수도 있고 불필요한 오버헤드가 발생할 수도 있습니다. 이 경우 list 또는 deque를 범용 스택으로 사용하는 것이 더 좋습니다.

In [ ]:
!pip install queue
In [ ]:
from queue import LifoQueue
s = LifoQueue()
s.put("eat")
s.put("sleep")
s.put("code")

s
In [ ]:
s.get()
In [ ]:
s.get()
In [ ]:
s.get()
In [ ]:
s.get_nowait()
In [ ]:
s.get()

대기열(FIFO)

FIFO 대기열에 대한 실제 비유는 다음과 같습니다.

PyCon 등록 첫날 PyCon 컨퍼런스 배지를 받기 위해 줄지어 있는 Pythonistas를 상상해 보세요. 새로운 사람들이 컨퍼런스 장소에 입장하고 배지를 받기 위해 줄을 서면 대기열 뒤쪽에 줄을 서게 됩니다(인큐). 개발자는 배지와 컨퍼런스 기념품 가방을 받은 후 대기열 맨 앞에서 줄을 종료합니다(대기열에서 제외).

큐 데이터 구조의 특성을 기억하는 또 다른 방법은 이를 파이프로 생각하는 것입니다. 탁구공을 한쪽 끝에 추가하면 다른 쪽 끝으로 이동하여 제거합니다. 공이 대기열(단단한 금속 파이프)에 있는 동안에는 공을 잡을 수 없습니다. 대기열에 있는 공과 상호 작용하는 유일한 방법은 파이프 뒤쪽에 새 공을 추가(enqueue)하거나 앞쪽에서 제거(dequeue)하는 것입니다.

큐는 스택과 유사합니다. 차이점은 항목이 제거되는 방식에 있습니다. 큐를 사용하면 최근에 추가된 항목을 제거합니다(FIFO). 하지만 스택을 사용하면 최근에 추가된 가장 항목을 제거합니다(LIFO ).

list: 대기열이 너무 심해요

일반 list을 대기열로 사용하는 것이 가능하지만 이는 수행 관점에서는 적합하지 않습니다

In [ ]:
q = []
q.append("eat")
q.append("sleep")collections.deque: 빠르고 강력한 대기열
q.append("code")

q
In [ ]:
# Careful: This is slow!
q.pop(0)

collections.deque: 빠르고 강력한 대기열

deque는 양쪽 끝에서 요소 추가 및 제거를 동일하게 지원하므로 대기열과 스택 역할을 모두 수행할 수 있습니다.

In [ ]:
from collections import dequequeue.Queue: 병렬 컴퓨팅을 위한 잠금 의미론
q = deque()
q.append("eat")
q.append("sleep")
q.append("code")

q
In [ ]:
q.popleft()
In [ ]:
q.popleft()
In [ ]:
q.popleft()
In [ ]:
q.popleft()

queue.Queue: 병렬 컴퓨팅을 위한 잠금 의미론

queue 모듈에는 병렬 컴퓨팅에 유용한 다중 생산자, 다중 소비자 대기열을 구현하는 여러 다른 클래스가 포함되어 있습니다.

사용 사례에 따라 잠금 의미 체계가 도움이 될 수도 있고 불필요한 오버헤드가 발생할 수도 있습니다. 이 경우 collections.deque를 범용 대기열로 사용하는 것이 더 좋습니다:

In [ ]:
from queue import Queue
q = Queue()
q.put("eat")
q.put("sleep")
q.put("code")

q
In [ ]:
q.get()
In [ ]:
q.get()
In [ ]:
q.get()
In [ ]:
q.get_nowait()
In [ ]:
q.get()

multiprocessing.Queue: 공유 작업 대기열

multiprocessing.Queue은 여러 동시 작업자가 대기열에 있는 항목을 병렬로 처리할 수 있도록 하는 공유 작업 대기열 구현입니다. 프로세스 기반 병렬화는 단일 인터프리터 프로세스에서 일부 형태의 병렬 실행을 방지하는 전역 인터프리터 잠금(GIL)으로 인해 CPython에서 널리 사용됩니다.

In [ ]:
!pip install multiprocessing
In [ ]:
from multiprocessing import Queue
q = Queue()
q.put("eat")
q.put("sleep")
q.put("code")

q
In [ ]:
q.get()
In [ ]:
q.get()
In [ ]:
q.get()
In [ ]:
q.get()
In [ ]:
출처 : https://realpython.com/python-data-structures/