Python

[Python] 자료구조

sian han 2025. 9. 25. 18:17

학습 자료 : https://docs.python.org/ko/3.13/tutorial/datastructures.html

자료구조

리스트

파이썬의 리스트는 객체지향적으로 설계되어 있어 다양한 내장 메서드를 제공한다. 아래 메서드들은 대부분 리스트를 제자리에서(in-place) 수정하고 None 을 반환한다.

요소 추가 및 확장

  • list.append(x): 리스트 끝에 하나의 요소를 추가한다.
  • list.extend(iterable): 리스트 끝에 다른 iterable(리스트, 튜플 등)의 모든 요소를 추가한다.

요소 삽입 및 삭제

  • list.insert(i, x): 특정 인덱스 i에 요소를 삽입한다.
  • list.remove(x): 리스트에서 첫 번째로 발견된 x의 값을 삭제한다.
  • list.pop([i]): 특정 인덱스의 i의 요소를 삭제하고 그 요소를 반환한다. 인덱스를 생략하면 마지막 요소를 삭제하고 반환한다.

리스트 정보 조회

  • list.index(x[, start[, end]]): 리스트에서 x가 처음 나타나는 인덱스를 반환한다. start와 end로 탐색 범위를 지정할 수 있다.
  • list.count(x): 리스트에 x가 몇번 등장하는지 횟수를 반복함

리스트 정렬 및 뒤집기

  • list.sort(*, key=None, reverse=False): 리스트를 제자리에서 정렬한다. reverse=True 로 내림차순 정렬이 가능하다.

리스트 복사

  • list.copy(): 리스트의 얕은 복사본을 반환한다.

  1. 반환값 None: append(), sort(), reverse() 와 같이 리스트를 직접 수정하는 대부분의 메서드는 별도의 값을 반환하지 않고 None을 반환한다. 이는 제자리에서 수정하는 메서드라는 것을 나타내느 파이썬의 설계 원칙이다.
  2. 비교 가능성: 파이썬은 서로 다른 자료형을 비교할 수 없다. 따라서 [1, 'hello']처럼 정수와 문자열이 섞여 있는 리스트는 sort() 메서드로 정렬할 수 없다. 이는 자바에서 int와 String 을 직접 비교할 수 없는 것과 같은 개념이다.

리스트를 Stack 으로 사용하기

스택은 마지막에 들어간 것이 가장 먼저 나오는 LIFO 구조를 가지고 있다. 파이썬의 list는 이 스택 기능을 아주 쉽게 구현할 수 있다.

  • append() : 스택의 맨 위에 항목을 추가한다.
  • pop() : 스택의 맨 위에서 항목을 꺼낸다

Queue 로 리스트 사용하기

큐는 먼저 들어간 것이 먼저 나오는 FIFO 구조이다.

  • list는 큐로 사용하기에 비효율적이다. 따라서 큐를 구현할 때는 collections 모듈의 deque를 사용해야한다. deaue는 양쪽 끝에ㅓ 데이터를 넣고 빼는데 최적화 되어있어, 큐처럼 사용할 때 훨씬 빠르다
  • append() : 줄의 맨 뒤에 추가(새로운 사람이 줄을 서는 것)
  • popleft() : 줄의 맨 앞에서 꺼낸다

⭐⭐⭐리스트 컴프리핸션(List Comprehensions)

리스트 컴프리헨션은 리스트를 만드는 아주 간결한 방법이다. for 반복문이나 map, filter 함수를 여러줄에 걸쳐 쓰는 대신, 한 줄로 깔끔하게 리스트를 만들 수 있다.

  • 기본형식은 [표현식 for 항목 in 이터러블 if 조건] 이다.
  • 리스트 컴프리헨션의 장점
    • 코드가 짧고 간결하다
    • 읽기 쉽다
    • 속도가 빠르다 : 파이썬이 내부적으로 최적화해서 일반적인 for 루프보다 더 빠르게 작동한다.

for문으로 숫자의 제곱 리스트를 만드는 것보다 아래와 같이 한줄로 쓰는 것이 훨씬 간단하다.

squares = [x**2 for x in range(10)] 
# 파이썬에서 **는 거듭제곱 연산자이다. 즉 x**2는 x의 2승임

여러 for문을 중첩해서 써야 할 때도 한 줄로 쓸 수 있다.

[(x,y) for x in [1,2,3] for y in [3,1,4] if x !=y]

위 코드는 두 개의 for 문과 하나의 if 문을 사용한 것과 완전히 똑같다.

중첩된 리스트 컴프리헨션

중첩된 컴프리헨션은 바깥쪽 대괄호 안에 [표현식 for ...] 형태의 또 다른 컴프리헨션이 들어가는 구조임

matrix = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
]

[[row [i] for row in matrix] for i in range(4)]
  • 위 코드는 세단계로 분해해서 이해할 수 있다.
  • 바깥쪽 for 루프 : for in range(4)는 i를 0,1,2,3 으로 순회하며 네 번 반복함. 이는 전치된 행렬의 각 열을 생성하는 역할을 한다.
  • 안쪽 리스트 컴프리헨션: [row[i] for row in matrix]는 바깥 루프의 i 값에 따라 각 행에서 i번째 요소를 가져와 새로운 리스트를 만든다.
    • i가 0일 때: [matrix[0][0], matrix[1][0], matrix[2][0]]
    • i가 1일 때: [matrix[0][1], matrix[1][1], matrix[2][1]]
  • 결과적으로 바깥쪽 루프가 반복될 때마다 생서오딘 새로운 리스트가 최종 리스트에 추가된다. 이 방법은 for 루프를 세 번 중첩해서 쓰는것보다 훨씬 간결하고 직관적이다.

del 문 : 리스트에서 항목 제거하기

del 문은 리스트에서 인덱스를 이용해 특정 항목을 제거하는 데 사용된다. pop() 메서드는 항목을 제거하고 그 값을 반환하지만, del은 반환값이 없다.

  • 항목 제거 : del a[0]은 a 리스트의 첫번째 항목을 삭제한다.
  • 슬라이스 제거 : del a[2:4]는 a 리스트의 2번 인덱스부터 4번 인덱스 이전까지의 항목들을 삭제한다.
  • 리스트 비우기 : del a[:]는 리스트의 모든 항목을 삭제하여 빈 리스트로 만든다

튜플과 시퀀스

튜플리스트와 유사한 시퀀스형 자료형이지만 결정적이 차이점은 불변이라는 점이다.

  • 생성: 튜플은 쉼표로 구분된 값들로 만든다.
  • 불변성: t[0] = 88888 처럼 튜플의 요소를 변경할 수 없다. 이는 자바에서 final 키워드로 선언된 객체의 참조를 변경할 수 없는 것과 유사하다.
  • 용도: 튜플은 보통 이질적인 데이터를 묶을 때 사용한ㄷ다. 함수의 반환값이 여러개일때, 이 값들을 묶어서 반환하는 용도로도 많이 사용한다.

집합(Set)

집합은 중복된 요소를 허용하지 않는 순서가 없는 컬렉션이다. 기본적인 용도는 멤버십 검사와 중복 엔트리 제거이다.

  • 생성: set() 함수로 만든다. 빈 집합은 반드시 set() 으로 만들어야 한다.

    주요 용도

  • 중복 제거: 리스트를 set으로 변환하면 중복된 값이 자동으로 사라짐
  • 멤버십 검사: 특정 요소가 집합에 있는지 in 연산자로 확인하는 속도가 매우 빠르다
# 1. 집합 생성
fruits = {'apple', 'orange', 'banana', 'apple', 'pear'}
print(fruits)

# 출력: {'pear', 'orange', 'apple', 'banana'}
# 'apple'이 하나만 남고 순서가 뒤죽박죽인 것을 볼 수 있다.

# 2. 빈 집합 생성
empty_set = set()
print(empty_set)
# 출력: set()

# 리스트를 집합으로 변환하여 중복 제거
numbers = [1, 2, 3, 2, 1, 4]
unique_numbers = set(numbers)
print(unique_numbers)
# 출력: {1, 2, 3, 4}

# 문자열을 집합으로 변환 (각 문자가 요소가 됨)
my_string = "hello"
letters = set(my_string)
print(letters)
# 출력: {'h', 'e', 'l', 'o'}
# 'l'이 하나만 남습니다.

딕셔너리

딕셔너리는 키와 값 쌍으로 이루어진 데이터의 집합이다. 순서가 없는 데이터 구조이고, 인덱스를 숫자가 아닌 키로 접근한다는 점에서 리스트나 튜플과 다르다.

  • key: 키는 중복될 수 없으며, 불변 자료형만 가능하다. 따라서 리스트는 가변적이므로 키가 될 수 없다.
  • value: 어떤 자료형이든 가능하며, 중복도 혀용된다.

딕셔너리 생성 : {} 중괄호를 사용하여 키: 값 쌍을 나열해 만든다. 빈 딕셔너리는 {}로 생성한다.

# 빈 딕셔너리
empty_dict = {}

# 키-값 쌍을 가진 딕셔너리
 tel = {'jack': 4098, 'sape': 4139}

데이터 추가, 접근 및 수정

# 빈 딕셔너리 생성
tel = {}

# 1. 데이터 추가(키가 없을 때)
tel['jack'] = 4098
tel['jack'] = 4139
tel['jack'] = 4127
print("데이터 추가 후:", tel)

# 2.데이터 접근
print("\n'jack'의 전화번호:", tel['jack']) 

# 3. 데이터 수정 (키가 이미 있을 때)
# guido 의 전화번호를 4127에서 4128로 변경
tel['guido'] = 4128
print("\n데이터 수정 후:", tel)

# 4. 데이터 삭제
del tel['sape']
print("\n데이터 삭제 후:", tel)

# 5. 존재하지 않는 키에 접근 시도
# 이 코드는 오류를 발생시킵니다. 주석 처리
# print(tel['terry'])
데이터 추가 후: {'jack': 4098, 'sape': 4139, 'guido': 4127}

'jack'의 전화번호: 4098

데이터 수정 후: {'jack': 4098, 'sape': 4139, 'guido': 4128}

데이터 삭제 후: {'jack': 4098, 'guido': 4128}

루프 테크닉

파이썬은 루프를 더 효율적이고 읽기 쉽게 만드는 다양한 내장함수를 제공한다.

1. items(): 딕셔너리 루프

딕셔너리에서 키와 값을 동시에 순회할 때 items()메서드를 사용한다.
이 메서드는 튜플 형태의 키,값 쌍을 반환한다.

knithgts = {'gallahad': 'the pure', 'robin': 'the brave'}
for k, v in knights.items():
    print(k, v)
# 출력:
# gallahad the pure
# robin the brave

2. enumerate(): 인덱스와 값 동시에 얻기

enumerate() 함수는 리스트나 튜플을 순회할 때 인덱스와 값을 함께 얻을 수 있게 해줌

for i, v in enumerate(['tic', 'tac', 'toe']):
    print(i, v)
# 출력:
# 0 tic
# 1 tac
# 2 toe

별도의 카운터 변수를 만들고 1씩 증가시키는 것보다 훨씬 간편하고 직관적이다.

3. reversed() 와 sorted(): 순서 바꾸기

이 두함수는 원본 데이터를 훼손하지 않고 원하는 순서로 데이터를 처리할 수 있어 매우 유용하다.

  • reversed(): 시퀀스를 역순으로 순회하게 해줌
    for i in reversed(range(1, 10, 2)):
      print(i)  # 9, 7, 5 , 3, 1 출력 
  • sorted(): 시퀀스를 정렬된 상태로 순회하게 해줌. 원본 리스트는 그대로 두고 새로운 정렬된 리스트를 반환함
    basket = ['apple', 'orange', 'apple']
    for i in sorted(basket):
      print(i)  # apple, apple, orange 출력

4. sorted(set()): 고유한 값만 정렬해서 순회하기

set()을 사용해 중복을 제거하고, sorted()로 정렬하여 순회하는 방식은 파이썬에서 자주 사용되는 관용구이다.

basket = ['apple', 'orange', 'apple', 'pear', 'orange', 'banana']
for f in sorted(set(basket)):
    print(f)

# 출력:
# apple
# banana
# orange
# pear

'Python' 카테고리의 다른 글

[Python] 모듈  (0) 2025.09.25
[Python] 조건문·반복문·함수  (0) 2025.09.25