Skip to content

6주차 · 자료구조

이번 주 목표는 자료구조 4개를 모두 외우는 것이 아니라, 먼저 아래 4가지를 분명히 구분하는 것입니다.

  • list순서 있는 여러 값을 번호(index)로 읽는다.
  • tuplelist와 비슷하지만 만든 뒤 값을 바꾸지 않는다.
  • dict번호가 아니라 key 이름으로 값을 찾는다.
  • set중복 제거와 포함 여부 확인에 쓴다.
  • append, pop, get, add처럼 지금 꼭 필요한 기본 동작을 사용할 수 있다.
  • for 반복문으로 list / tuple / dict를 순회하며 값을 읽고 간단한 누적·출력을 할 수 있다.
  • 문제를 보고 “이건 list / tuple / dict / set 중 무엇을 써야 하는가?”를 설명할 수 있다.

자료구조는 데이터를 정리해서 담는 방식입니다.

구조 선택이 결과 품질에 미치는 영향
flowchart TB
  A[같은 데이터] --> B[어떻게 담는가]
  B --> C[읽기 쉬운가]
  B --> D[수정이 쉬운가]
  B --> E[버그가 줄어드는가]

예를 들어 학생 이름 100명을 다룬다고 해 봅시다.

  • 순서대로 출력하려면 list
  • 학번으로 바로 찾으려면 dict
  • 중복 이름을 제거하려면 set

즉, 데이터는 같아도 담는 방식이 다르면 코드가 달라집니다.

2) 값을 꺼내는 방식부터 구분하기

Section titled “2) 값을 꺼내는 방식부터 구분하기”

처음 배우는 학생이 가장 먼저 구분해야 하는 것은 “이 구조에서 값을 어떻게 읽는가” 입니다.

구조값을 읽는 방식예시이 구조가 답하는 질문
listindex(번호)scores[0]“첫 번째 값은?”
tupleindex(번호)point[1]“두 번째 값은?”
dictkey(이름표)sensor["temp"]“temp 값은?”
set포함 여부"ok" in tags“이 값이 들어 있나?”

list는 순서가 있는 여러 값을 담는 가장 기본적인 자료구조입니다.

values = [12.4, 11.8, 12.9, 13.1, 12.2]
print(values[0]) # 첫 번째 값
print(values[-1]) # 마지막 값
인덱스01234
12.411.812.913.112.2
음수 인덱스-5-4-3-2-1
  • values[0] → 첫 번째 값
  • values[-1] → 마지막 값

슬라이싱으로 여러 값 한 번에 보기

Section titled “슬라이싱으로 여러 값 한 번에 보기”
values = [12.4, 11.8, 12.9, 13.1, 12.2]
print(values[1:4])

출력:

[11.8, 12.9, 13.1]

슬라이싱 규칙은 다음 한 줄로 기억하면 됩니다.

start <= index < end

즉, values[1:4]1번부터 시작해서 4번 직전까지 가져옵니다.

values = [12.4, 11.8, 12.9]
values[1] = 12.0
print(values) # [12.4, 12.0, 12.9]
동작코드의미
읽기values[0]번호로 값 읽기
구간 읽기values[1:3]여러 값 한 번에 가져오기
수정values[1] = 12.0기존 값 바꾸기
맨 끝 추가values.append(14.0)값 1개 추가
맨 끝 꺼내기values.pop()마지막 값을 꺼내며 삭제
길이 확인len(values)값이 몇 개인지 확인
values = [12.4, 11.8, 12.9]
values.append(14.0)
last = values.pop()
print(values) # [12.4, 11.8, 12.9]
print(last) # 14.0

4) tuple — list와 비슷하지만 바꾸지 않는 묶음

Section titled “4) tuple — list와 비슷하지만 바꾸지 않는 묶음”

tuple은 순서가 있는 값 묶음이지만, 만든 뒤에는 값을 바꾸지 않습니다.

  • 좌표 (x, y)
  • 날짜 (2026, 4, 9)
  • RGB 색 (255, 0, 0)
  • “읽기만 하고 수정하지 않을 값 묶음”
point = (3, 5)
print(point[0])
print(point[1])
# point[0] = 7 # TypeError
구조읽기수정어울리는 상황
list가능가능계속 바뀌는 데이터
tuple가능불가고정된 값 묶음
  • 읽는 방법은 list와 같다. → point[0]
  • 하지만 값 변경은 안 된다.
  • 처음 배우는 단계에서는 “읽기 전용 list 비슷한 것” 으로 이해해도 충분하다.

5) dict — 이름표(key)로 찾는 구조

Section titled “5) dict — 이름표(key)로 찾는 구조”

dict는 값을 번호로 찾지 않고, key 이름으로 찾는 자료구조입니다.

sensor = {"id": "A01", "temp": 23.4, "status": "ok"}
print(sensor["id"])
print(sensor["temp"])
sensor = {"id": "A01", "temp": 23.4}
print(sensor["id"]) # 읽기
sensor["status"] = "ok" # 새 key 추가
sensor["temp"] = 24.0 # 기존 key 값 수정
print(sensor)

없는 key는 get()으로 안전하게 읽기

Section titled “없는 key는 get()으로 안전하게 읽기”
sensor = {"id": "A01", "temp": 23.4}
print(sensor.get("owner", "미등록"))
sensor = {"id": "A01", "temp": 23.4}
if "temp" in sensor:
print(sensor["temp"])
동작코드의미
key로 읽기sensor["temp"]key 이름으로 값 읽기
추가/수정sensor["status"] = "ok"key:value 넣기
안전 조회sensor.get("owner", "미등록")없으면 기본값 반환
존재 확인"temp" in sensor이 key가 있는지 확인
길이 확인len(sensor)key가 몇 개인지 확인

6) set — 중복 제거와 포함 여부 확인

Section titled “6) set — 중복 제거와 포함 여부 확인”

set은 중복 없는 값 모음입니다.

tags = {"ok", "warn"}
tags.add("offline")
print("ok" in tags)
raw_tags = ["ok", "warn", "ok", "ok", "offline"]
unique_tags = set(raw_tags)
print(unique_tags)
print(sorted(unique_tags))
  • set(raw_tags) → 중복 제거
  • "ok" in unique_tags → 포함 여부 확인
  • sorted(unique_tags) → 보기 좋게 정렬해서 출력
동작코드의미
생성set(["ok", "ok", "warn"])중복 제거
추가tags.add("offline")값 1개 추가
포함 검사"ok" in tags값이 있는지 확인
정렬 출력sorted(tags)순서 있게 출력
길이 확인len(tags)고유 값 개수 확인

7) 자료구조를 반복문과 함께 읽기

Section titled “7) 자료구조를 반복문과 함께 읽기”

4주차의 for문은 range()와 함께 썼습니다.
이번 주부터는 숫자 범위 대신 자료구조 자체를 반복할 수 있어야 합니다.

반복 대상기본 형태반복마다 꺼내는 값
listfor value in values:각 원소
tuplefor value in point:각 원소
dictfor key in sensor:각 key
dict.items()for key, value in sensor.items():(key, value)

A. list 반복: 값을 하나씩 읽어 평균 준비하기

Section titled “A. list 반복: 값을 하나씩 읽어 평균 준비하기”
temperatures = [23.1, 22.8, 24.0, 23.7]
total = 0
for temp in temperatures:
print("current:", temp)
total += temp
average = total / len(temperatures)
print("average:", average)
  • temp에는 list의 원소가 하나씩 순서대로 들어갑니다.
  • range(len(temperatures))를 쓰지 않아도, 값 자체를 바로 꺼낼 수 있습니다.
  • 이런 방식이 읽기 전용 순회에서는 더 자연스럽고 실수가 적습니다.

B. tuple 반복: 고정된 값 묶음을 차례대로 읽기

Section titled “B. tuple 반복: 고정된 값 묶음을 차례대로 읽기”
point = (3, 5)
for value in point:
print("coord:", value)
  • tuple도 list처럼 for문으로 순회할 수 있습니다.
  • 단, tuple은 읽기만 하고 수정하지 않습니다.

C. dict 반복: key만 돌거나, key와 value를 함께 돌기

Section titled “C. dict 반복: key만 돌거나, key와 value를 함께 돌기”
sensor = {"A01": "OK", "A02": "WARN", "A03": "OK"}
for sensor_id in sensor:
print(sensor_id, sensor[sensor_id])
  • for sensor_id in sensor: 는 key를 하나씩 꺼냅니다.
  • value가 필요하면 sensor[sensor_id]로 다시 읽습니다.
sensor = {"A01": "OK", "A02": "WARN", "A03": "OK"}
for sensor_id, status in sensor.items():
print(sensor_id, status)
  • items()(key, value) 쌍을 꺼냅니다.
  • 그래서 출력·집계·검사에서는 items()가 더 편한 경우가 많습니다.

이제 4개 구조를 다시 비교해 보면 더 이해가 쉽습니다.

구조순서수정 가능값을 읽는 방식가장 먼저 떠올릴 사용처
list있음가능index여러 값을 순서대로 저장
tuple있음불가index고정된 값 묶음
dict있음*가능key이름으로 값 찾기
setindex 순서 없음가능포함 여부중복 제거

* Python 3.7+에서는 삽입 순서를 유지합니다.

9) 한 번 더 보면 좋은 method 참고표

Section titled “9) 한 번 더 보면 좋은 method 참고표”

아래는 지금 당장 외우기보다, 필요할 때 찾아보는 2차 참고용입니다.

method의미예시
insert(i, x)원하는 위치에 삽입nums.insert(1, 15)
extend(seq)여러 값 이어 붙이기nums.extend([50, 60])
remove(x)값이 같은 첫 원소 삭제nums.remove(20)
sort()리스트 자체 정렬nums.sort()
count(x)값 개수 세기nums.count(10)
index(x)값의 위치 찾기nums.index(30)
method의미예시
keys()key들 보기sensor.keys()
values()value들 보기sensor.values()
items()(key, value) 쌍 보기sensor.items()
update(other)여러 key를 한꺼번에 반영sensor.update({"status": "ok"})
pop(key)key를 꺼내며 삭제sensor.pop("temp")
method의미예시
update(seq)여러 값 추가tags.update(["ok", "hold"])
remove(x)값 삭제 (없으면 에러)tags.remove("warn")
discard(x)값 삭제 (없어도 조용히 통과)tags.discard("warn")

Bad

lookup = {"A01": 23.4}
print(lookup["A03"]) # KeyError

Good

print(lookup.get("A03", "missing"))
if "A03" in lookup:
print(lookup["A03"])
else:
print("A03 없음")

Bad

a = [1, 2, 3]
b = a
b[0] = 99
print(a) # [99, 2, 3]
리스트 참조 vs 복사
flowchart LR
  subgraph "b = a (참조 공유)"
    direction TB
    varA1["변수 a"] --> list1["[1, 2, 3]"]
    varB1["변수 b"] --> list1
  end
  subgraph "b = a.copy() (독립 복사)"
    direction TB
    varA2["변수 a"] --> list2["[1, 2, 3]"]
    varB2["변수 b"] --> list3["[1, 2, 3]"]
  end

Good

a = [1, 2, 3]
b = a.copy()
b[0] = 99
print(a) # [1, 2, 3]
  1. 자료형부터 확인: print(type(x), x)
  2. 길이 확인: print(len(x))
  3. dict는 key 읽기 전 in 또는 get() 확인
  4. set은 sorted()로 출력해 보기
  5. list 복사는 a.copy()로 했는지 확인
예제 1 · list 읽기와 tuple 읽기 코드를 실행하고 출력 결과를 확인하세요.
Ready
  1. list를 만들고 첫 값과 마지막 값을 읽습니다.
  2. 슬라이싱으로 여러 값을 한 번에 가져옵니다.
  3. list는 값을 수정하고 append()로 새 값을 추가할 수 있습니다.
  4. tuple은 index로 읽을 수 있지만 수정은 하지 않습니다.
예제 2 · 단순한 dict key/value 조회 코드를 실행하고 출력 결과를 확인하세요.
Ready
  1. sensor는 key와 value로 이루어진 dict입니다.
  2. sensor["id"], sensor["temp"]처럼 key 이름으로 값을 읽습니다.
  3. sensor["status"] = "warn"은 기존 값 수정입니다.
  4. sensor["location"] = "lab-1"은 새 key 추가입니다.
  5. get()은 없는 key를 안전하게 읽을 때 씁니다.
  6. "temp" in sensor는 key 존재 여부를 확인합니다.
예제 3 · set으로 중복 제거하기 코드를 실행하고 출력 결과를 확인하세요.
Ready
  1. 원본은 중복이 있는 list입니다.
  2. set(tags)로 중복을 제거합니다.
  3. set은 순서가 일정하지 않을 수 있으므로 sorted()로 출력합니다.
  4. add()로 값을 하나 추가할 수 있습니다.
  5. in으로 포함 여부를 확인할 수 있습니다.
예제 4 · list/dict를 반복문으로 순회하기 코드를 실행하고 출력 결과를 확인하세요.
Ready
  1. for temp in temperatures:는 list 원소를 순서대로 꺼냅니다.
  2. total += temp로 누적하면 평균 계산 준비가 됩니다.
  3. dict는 items()를 사용하면 key와 value를 함께 꺼낼 수 있습니다.
  4. 이 패턴은 다음 주 파싱 결과를 dict/list로 다룰 때 바로 이어집니다.
실수증상이유해결
tuple을 list처럼 수정TypeErrortuple은 수정 불가수정이 필요하면 list 사용
슬라이싱 끝값 포함으로 착각결과가 한 칸 다름끝 index는 포함되지 않음start <= i < end 기억
dict 없는 key 즉시 조회KeyError방어 코드 없음get() 또는 if key in dict
set에 순서 기대출력 순서가 달라 보임set은 순서형 아님sorted(set_data) 사용
b = a를 복사로 착각원본까지 바뀜같은 list를 가리킴a.copy() 사용

문제: 점수 5개가 들어 있는 list에서 최고점, 최저점, 평균을 계산해 출력하세요.

실습 문제 1 · list 통계 내기 코드를 실행하고 출력 결과를 확인하세요.
Ready

해야 할 일

  • highest, lowest, average 변수를 만드세요.
  • 세 값을 모두 출력하세요.

힌트

  • max(scores), min(scores), sum(scores), len(scores)를 사용할 수 있습니다.
  • 평균은 sum(scores) / len(scores) 입니다.

C와 비교: 배열/struct와 Python 자료구조는 이렇게 다릅니다

Section titled “C와 비교: 배열/struct와 Python 자료구조는 이렇게 다릅니다”
항목CPython기억할 점
순차 데이터배열 int a[3]list / tuplePython은 크기와 타입이 더 유연하다
레코드 데이터structdictPython은 key 문자열로 바로 접근
중복 제거직접 구현setPython은 집합이 기본 제공
수정 가능성선언 방식에 따라 다름list/dict/set 수정 가능, tuple 불가선택이 문법에 드러난다
struct Sensor {
char id[10];
double temp;
};
struct Sensor s = {"A01", 23.4};
printf("%s %.1f\n", s.id, s.temp);