알고리즘 문제에서 2차원 배열을 사용하는 문제를 자주 만난다
평소 헷갈렸던 모든 것을 정리해보자
2차원 리스트: 선언
기본적으로 2차원 리스트란 대괄호([ ]) 2개로 만드는 리스트를 말한다. 즉, 리스트 안에 리스트가 포함된 형태다
1차원 리스트와는 달리 2차원 리스트는 (행,열)의 개념으로 표현한다.
1. for문
for문을 통해 2차월 리스트를 선언하려면 이중for문을 써야한다.
다시 말해, 바깥 for문은 row를 만들고, 안쪽 for문은 col을 만드는 것이다
a = []
for i in range(3):
line = []
for j in range(4):
line.append(0)
a.append(line)
print(a)
#[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
#[[0, 0, 0, 0], #읽기 쉽게 세로로 써도 가능
# [0, 0, 0, 0],
# [0, 0, 0, 0]]
2. 리스트 표현식(1)
리스트가 리스트를 감싸는 형태로 할 때는 어디가 col인지, 어디가 row인지 잘 확인해야 한다
그래도 헷갈리면 입력 받고 print문으로 한 번 확인 하고나서 문제 풀기 시작하는 것도 좋다
a = [[0 for j in range(5)] for i in range(4)]
# [[]]안이 col, 밖이 row
# 0 0 0 0 0
# 0 0 0 0 0
# 0 0 0 0 0
# 0 0 0 0 0
3. 리스트 표현식(2)
a = [[0]*5 for i in range(4)]
# *col이고, for문을 도는 게 row
# 0 0 0 0 0
# 0 0 0 0 0
# 0 0 0 0 0
# 0 0 0 0 0
4. 주의할 점
n, m = 5, 4
a = [[0] * n] * m
# 0 0 0 0 0
# 0 0 0 0 0
# 0 0 0 0 0
# 0 0 0 0 0
이 실행 결과는 얼핏 *을 사용해도 2차원 배열 선언 자체는 잘 되는 것처럼 보인다.
하지만 이렇게 2차원 리스트를 선언할 경우에는 업데이트시에 문제가 발생한다
n, m = 5, 4
a = [[0] * n] * m
a[1][2] = 3 #값 수정시
for i in a:
for j in i:
print(j, end=" ")
print()
# 0 0 3 0 0
# 0 0 3 0 0
# 0 0 3 0 0
# 0 0 3 0 0
다음과 같이 인덱스로 접근해서 값을 업데이트한 경우에 의도한 바와는 달리 모든 a[i][[2]의 값이 3으로 바뀝니다. 이렇게 되는 이유는 *를 사용하면 a의 모든 원소들이 복사되기 때문이다. 이는 마치 아래처럼 리스트에 대한 *연산은 리스트 내 요소의 반복이 되는 것과 유사하다
a = [1,2,3]
print(a*3)
#[1, 2, 3, 1, 2, 3, 1, 2, 3]
n = 5
a = [0]*5 #[0, 0, 0, 0, 0]
a[3] = 1 #[0, 0, 0, 1, 0]
print(a)
결론은 1차원 리스트를 선언하는 것은 *를 써도 무방하지만, 2차원 배열을 선언할 때는 2중for문이나 리스트 표현식을 사용하는 게 좋겠다!
톱니형 리스트
#for문으로 선언 a = [3,1,4,2,3,1,4] b = [] for i in a: line = [] for j in range(i): line.append(0) b.append(line) print(b) #[[0, 0, 0], [0], [0, 0, 0, 0], [0, 0], [0, 0, 0], [0], [0, 0, 0, 0]] #리스트 표현식으로 선언 a = [[0] * i for i in [3,1,4,2,3,1,4]] print(a) #[[0, 0, 0], [0], [0, 0, 0, 0], [0, 0], [0, 0, 0], [0], [0, 0, 0, 0]]
2차원 리스트: 출력
1. print문 활용
print(*a, sep='\n')에서 *a는 리스트 a의 요소를 풀어서 전달하고, sep='\n'은 각 요소 사이의 구분자를 새 줄로 지정한다.
a = [[0 for i in range(2)] for j in range(5)]
print(*a, sep='\n')
# [0, 0]
# [0, 0]
# [0, 0]
# [0, 0]
# [0, 0]
2. pprint 사용
pprint 사용시에는 from, import가 필수다
왜 그런지는 모르겠으나 indent(들여쓰기)와 width(가로폭)까지 지정해줘야 아래의 모양으로 잘 출력된다..
from pprint import pprint
a = [[0 for i in range(2)] for j in range(5)]
pprint(a, indent=2, width=20)
# [ [0, 0],
# [0, 0],
# [0, 0],
# [0, 0],
# [0, 0]]
3. for문
이 코드도 2차원 리스트를 출력할 때 많이 사용한다.
외부 루프(바깥for문)에서는 각 행을, 내부 루프(안쪽for문)에서는 각 열의 요소를 출력한다. print(j, end=' ')는 각 요소를 공백('_띄우고_ ')으로 구분하여 출력한다.
a = [[0 for i in range(2)] for j in range(5)]
for i in a:
for j in i:
print(j, end=' ')
print()
# 0 0
# 0 0
# 0 0
# 0 0
# 0 0
4. for+range
a = [[0 for i in range(5)] for j in range(3)]
for i in range(len(a)): #행의 수만큼
for j in range(len(a[i])): #열의 수만큼
print(a[i][j], end=' ') #a[i][j]는 i번째 행, j번째 열의 요소
print()
# 0 0 0 0 0
# 0 0 0 0 0
# 0 0 0 0 0
cf. 2차원 리스트의 정렬은 sorted(), sort() 모두 사용한다.
sorted()는 새롭게 정렬된 iterable을 반환하므로, 변수에 담아서 사용해야 한다(기본적으로 원본 리스트에는 변화 없음)
(※ sort()는 원본 리스트를 변화시킨다. 반환값이 없으므로 변수에 담을 필요 없이 list.sort()로 쓰면 된다->print는 원본 리스트를 해야 )
sorted(iterable, key=정렬 함수, reverse=True or False)
-> reverse에서는 디폴트가 False(오름차순)이고, True는 내림차순이다
names = [
['bob', 'kim', 35],
['mary', 'yoon', 23],
['john', 'choi', 13]
]
print(sorted(names, key=lambda name: name[0])) #인덱스 0기준
print(sorted(names, key=lambda name: name[1])) #인덱스 1기준 오름차순 정렬
print(sorted(names, key=lambda name: name[2], reverse=True)) #인덱스 2기준 내림차순 정렬
# [['bob', 'kim', 35], ['john', 'choi', 13], ['mary', 'yoon', 23]]
# [['john', 'choi', 13], ['bob', 'kim', 35], ['mary', 'yoon', 23]]
# [['bob', 'kim', 35], ['mary', 'yoon', 23], ['john', 'choi', 13]]
'TIL' 카테고리의 다른 글
[TIL 2024. 03. 25] 소켓과 웹소켓 (0) | 2024.03.25 |
---|---|
[TIL 2024. 03. 22] OSI 7계층 (0) | 2024.03.22 |
[TIL 2024. 03. 20] 데이터베이스와 DBMS (0) | 2024.03.20 |
[TIL 2024. 03.19] 프로세스와 스레드 (0) | 2024.03.19 |
[TIL 2024. 03. 18] CS(1) (0) | 2024.03.19 |