1. 이중 for문
반복문 안에 또다른 반복문이 중첩될 수 있다.
- 지금까지는 일차원적인 반복에 대해서만 살펴보았다. 예를들면, 0부터 3까지 4번 반복하는 것과 같은 것을 말한다.
- 만약 4번 반복하는 것 자체를 4번 반복하는, 즉 4 x 4번(총 16번)을 반복하는 상황에 대해서는 어떻게 나타낼 수 있을까?
- 이는 반복문 안에 반복문을 중첩으로 작성하여 나타낼 수 있다.
for a in range(4):
print(f"a가 {a}일 때")
for b in range(4):
print(f"b는 {b}")
a가 0일 때
b는 0
b는 1
b는 2
b는 3
a가 1일 때
b는 0
b는 1
b는 2
b는 3
a가 2일 때
b는 0
b는 1
b는 2
b는 3
a가 3일 때
b는 0
b는 1
b는 2
b는 3
- 위 결과를 표로 나타내면 아래와 같다.
a b
0 -> 0 1 2 3
1 -> 0 1 2 3
2 -> 0 1 2 3
3 -> 0 1 2 3
총 16번 반복
이러한 이중 for문은 왜 필요할까? 바로 다음에 나오는 이차원 리스트라는 개념에서 사용하기 위함이다.
2. 이차원 리스트
2-1. 이차원 리스트란?
- 지금까지는 1차원 직선 형태로만 리스트를 사용해왔다 (ex. [1, 2, 3, 4, 5]). 하지만 2차원 평면 형태로도 리스트를 사용할 수 있다.
- 이차원 리스트란 리스트를 원소로 가지는 리스트를 의미한다.
- 이차원 리스트는 행렬(Matrix)라고도 하며, 가로와 세로 크기를 가진다.
- 이차원 리스트는 다음과 같이 표현할 수 있다.
- 크게 어려운 개념이 아니라, 단순히 리스트 안에 리스트가 중첩된 형태일 뿐이라는 것만 기억하자.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
print(matrix)
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
- 또한 가독성을 위해 줄바꿈을 입력하여 행렬의 형태로 작성해도 된다.
- 이차원 리스트는 인덱스를 통해 각 내부 리스트에 접근 가능합니다.
# matrix = [[3, 7, 9], [4, 2, 6], [8, 1, 5]] 와 같다. (줄바꿈만 한 것이다.)
matrix = [
[3, 7, 9],
[4, 2, 6],
[8, 1, 5]
]
print(matrix) # [[3, 7, 9], [4, 2, 6], [8, 1, 5]]
print(matrix[0]) # [3, 7, 9]
print(matrix[2]) # [8, 1, 5]
[[3, 7, 9], [4, 2, 6], [8, 1, 5]]
[3, 7, 9]
[8, 1, 5]
2-2. 각 원소 접근 및 수정
- 만약 내부 리스트의 각 원소(ex. 1, 2, 3 …)까지 접근하려면 어떻게 해야 할까?
- 대괄호([])를 연속으로 작성하여, matrix[행][열]과 같은 방식으로 이차원 리스트 각 원소에 접근한다.
- 이를 이용해 접근 뿐만 아니라, 이차원 리스트의 각 원소 값을 수정할 수도 있다.
matrix = [
[1, 8, 4],
[7, 3, 9],
[5, 2, 6]
]
print(matrix[0][0]) # 1
print(matrix[1][2]) # 9
matrix[0][2] = 0
print(matrix) # [[1, 8, 0], [7, 3, 9], [5, 2, 6]]
1
9
[[1, 8, 0], [7, 3, 9], [5, 2, 6]]
2-3. 이차원 리스트 순회
- 아래와 같은 3 x 4 이차원 리스트가 있다.
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 0, 1, 2]
]
- matrix에 담긴 모든 원소를 출력하고 싶다면 어떻게 할 수 있을까?
- 아래처럼 인덱스를 통해 각각의 원소에 접근하여, 모든 값을 출력하면 된다.
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 0, 1, 2]
]
print(matrix[0][0], matrix[0][1], matrix[0][2], matrix[0][3])
print(matrix[1][0], matrix[1][1], matrix[1][2], matrix[1][3])
print(matrix[2][0], matrix[2][1], matrix[2][2], matrix[2][3])
1 2 3 4
5 6 7 8
9 0 1 2
- 하지만 이차원 리스트의 행, 열의 크기가 커지게 되면 일일히 인덱스를 통해 접근 하기 불편하다. (만약 100 x 100이면 언제 다 쓰지?)
- 따라서 위에서 학습했던 중첩 반복문을 이용하여 쉽고 편하게 이차원 리스트 원소를 순회할 수 있다.
- 이차원 리스트를 가로로 순회한다고 생각하면 간단하다.
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 0, 1, 2]
]
for i in range(3): # 3행
for j in range(4): # 4열
print(matrix[i][j], end=" ")
print() # 하나의 행을 작성하고 아래로 개행하기 위함
1 2 3 4
5 6 7 8
9 0 1 2
- 이중 for문을 이용하면 이차원 리스트를 순회할 수 있다.
- i는 몇 번째 행인지, j는 몇 번째 열인지를 나타내는 변수이다.
- i가 0일 때 j는 0~3을 순회하고, i가 1일 때 j는 0~3을 순회하고, i가 2일 때 j는 0~3을 순회한다.
- 즉, i를 기준으로(행을 기준으로) j를 순회하는(열을 순회하는) 방식이라고 할 수 있다.
2-4. [예제] 모든 원소의 합 구하기
- 이차원 리스트 순회 개념을 적용하여, 모든 원소들의 총합을 구할 수 있다.
- 아래와 같은 3 x 4 이차원 리스트가 있다.
matrix = [
[0, 5, 3, 1],
[4, 6, 10, 8],
[9, -1, 1, 5]
]
- 순회를 이용해, 이차원 리스트의 총합을 구하는 방법은 아래와 같다.
matrix = [
[0, 5, 3, 1],
[4, 6, 10, 8],
[9, -1, 1, 5]
]
total = 0
for i in range(3):
for j in range(4):
total += matrix[i][j]
print(total)
51
2-5. [심화] 이차원 리스트의 델타(delta) 탐색
- 이차원 리스트의 순회 문제에서 많이 등장하는 유형으로 상하좌우 탐색이 있다.
- 행렬을 순회하며 각 지점에서 상하좌우에 위치한 다른 지점을 조회하거나 이동하는 방식이다.
- 이차원 리스트의 인덱스의 조작을 통해서 상하좌우 탐색을 할 수 있다.
- 상(위쪽)은 행 인덱스만 -1을 하면 된다. 하(아래쪽)는 행 인덱스만 +1을 하면 된다.
- 좌(왼쪽)는 열 인덱스만 -1을 하면 된다. 우(오른쪽)는 열 인덱스만 +1을 하면 된다.
- 행 인덱스는 보통 x 혹은 r로 나타내고, 열 인덱스는 보통 y 혹은 c로 나타낸다.
- 따라서 행과 열의 변화 값 +1, -1을 델타 값이라고 하며, dx 혹은 dr과 dy 혹은 dc로 나타낸다.
# 상하좌우 델타 값
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
혹은
dr = [-1, 1, 0, 0]
dc = [0, 0, -1, 1]
- 위의 델타 값을 이용해 상하좌우 이동을 코드로 나타내면 아래와 같다.
- 아래의 nx와 ny는 현재 좌표 (x, y)에서 방향에 따른 델타 값만큼 이동한 새로운 좌표를 지칭하는 변수다.
# 상(위쪽)
nx = x + dx[0]
ny = y + dy[0]
# 하(아래쪽)
nx = x + dx[1]
ny = y + dy[1]
# 좌(왼쪽)
nx = x + dx[2]
ny = y + dy[2]
# 우(오른쪽)
nx = x + dx[3]
ny = y + dy[3]
- 이동 후에는 반드시 새로운 위치가 이차원 리스트의 범위를 벗어나지 않는지 확인해야 한다.
- 범위를 벗어나지 않는다면 기존 x값을 nx로, y값을 ny로 갱신한다.
# 범위 확인 후 갱신
# 여기서 n과 m은 각각 행과 열의 길이를 말한다.
if 0 <= nx < n and 0 <= ny < m:
x = nx
y = ny
정리하면, 이차원 리스트의 모든 원소에 대해 아래 두 과정을 반복하면서 상하좌우 탐색을 한다.
1. 상하좌우 각 방향에 해당하는 dx, dy 값만큼 델타 이동
2. 이동한 nx, ny가 이차원 리스트의 범위를 넘지 않는다면 갱신
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
n, m = 3, 3
# 상, 하, 좌, 우
dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
# 이차원 리스트 순회
for x in range(n):
for y in range(m):
# 1. 상하좌우 각 방향에 해당하는 델타 이동
for i in range(4):
nx = x + dx[i]
ny = y + dy[i]
# 2. 이차원 리스트 범위를 넘지 않으면 갱신
if 0 <= nx < n and 0 <= ny < m:
x = nx
y = ny
- 추가적으로 상하좌우에 대각까지 더해진 8 방향 탐색도 있다.
- 좌상, 좌하, 우상, 우하까지 나타내는 델타 값이 추가되며, 이 역시 인덱스 조작을 통해 가능하다.
# 상, 하, 좌, 우, 좌상, 좌하, 우상, 우하
dx = [-1, 1, 0, 0, -1, 1, -1, 1]
dy = [0, 0, -1, 1, -1, -1, 1, 1]
'Python' 카테고리의 다른 글
API를 활용한 서버 데이터 수집 & 분석 (0) | 2024.04.07 |
---|---|
객체지향 프로그래밍(OOP) (0) | 2024.04.07 |
모듈 (0) | 2024.03.31 |
파이썬 메서드와 내장함수 (1) | 2024.03.31 |
함수(Function) (0) | 2024.03.31 |