코딩도장_Unit 23. 2차원 리스트 사용하기

김민주·2022년 1월 1일
0

AIFFEL_풀잎스쿨

목록 보기
19/23
post-thumbnail
  • 2차원 리스트는 가로X세로 형태
  • 행(row)과 열(column) 모두 0부터 시작

23.1 2차원 리스트를 만들고 요소에 접근하기

  • 2차원 리스트는 리스트 안에 리스트를 넣어서 만든다.
  • 안쪽의 각 리스트는 콤마(,)로 구분
    • 리스트 = [[값, 값], [값, 값], [값, 값]]
# 가로2, 세로3의 2차원 리스트
>>> a = [[10, 20], [30, 40], [50, 60]]
>>> a
[[10, 20], [30, 40], [50, 60]]

# 알아보기 쉽게 3줄로 입력해도 무방
a = [[10, 20],
     [30, 40],
     [50, 60] ]

23.1.1 2차원 리스트의 요소에 접근하기

  • 2차원 리스트의 요소에 접근하거나 값을 할당할 때는 리스트 뒤에 대괄호([])를 두 번 사용하며 [] 안에 세로(row) 인덱스와 가로(column) 인덱스를 지정
    • 리스트[세로인덱스][가로인덱스]
    • 리스트[세로인덱스][가로인덱스] = 값
>>> a = [[10, 20], [30, 40], [50, 60]]
>>> a[0] [0]            # 세로 인덱스 0, 가로 인덱스 0인 요소 출력
10
>>> a[1][1]           # 세로 인덱스 1, 가로 인덱스 1인 요소 출력
40
>>> a[2][1]           # 세로 인덱스 2, 가로 인덱스 0인 요소 출력
60
>>> a[0][1] = 1000    # 세로 인덱스 0, 가로 인덱스 1인 요소에 값 할당
>>> a[0][1]
1000

📎 참고) 톱니형 리스트
파이썬에서는 가로 크기가 불규칙한 톱니형 리스트(jagged list)도 만들 수 있다.

# 가로 크기(행의 요소 개수) 가 제각각
a = [[10, 20],  
     [500, 600, 700],
     [9],
     [30, 40],
     [8],
     [800, 900, 1000]]
# append 메서드를 사용하여 생성
>> a = []
>> a.append([])
>> a[0].append(10)
>> a[0].append(20)
>> a.append([])
>> a[1].append(500)
>> a[1].append(600)
>> a[1].append(700)
>> a
[[10, 20], [500, 600, 700]]

📎 참고) 2차원 튜플
튜플 안에 튜플을 넣는 방식, 튜플 안에 리스트를 넣는 방식, 리스트 안에 튜플을 넣는 방식 등이 가능

  • 튜플 = ((값, 값), (값, 값), (값, 값))
  • 튜플 = ([값, 값], [값, 값], [값, 값])
  • 리스트 = [(값, 값), (값, 값), (값, 값)]
a = ((10, 20), (30, 40), (50, 60))    # 튜플 안에 튜플을 넣은 2차원 튜플
b = ([10, 20], [30, 40], [50, 60])    # 튜플 안에 리스트를 넣음
c = [(10, 20), (30, 40), (50, 60)]    # 리스트 안에 튜플을 넣음

튜플은 내용 변경 불가

a[0][0] = 500        # 안쪽 튜플 변경할 수 없음. TypeError 발생
a[0] = (500, 600)    # 바깥쪽 튜플 변경할 수 없음. TypeError 발생
b[0][0] = 500        # 안쪽 리스트 변경할 수 있음
b[0] = (500, 600)    # 바깥쪽 튜플 변경할 수 없음. TypeError 발생
c[0][0] = 500        # 안쪽 튜플 변경할 수 없음. TypeError 발생
c[0] = (500, 600)    # 바깥쪽 리스트 변경할 수 있음

📎 참고) 알아보기 쉽게 출력하기
2차원 리스트를 출력하면 한 줄로 쭉 붙어서 출력된다.

>> a = [[10, 20], [30, 40], [50, 60]]
>> a
[[10, 20], [30, 40], [50, 60]]

2차원 리스트의 사각형 구조를 유지하도록 출력하려면 pprint 모듈의 pprint 함수를 사용

>> from pprint import pprint
>> pprint(a, indent=4, width=20)  # indent는 들여쓰기 칸 수, width는 가로 폭
[   [10, 20],
    [30, 40],
    [50, 60]]

23.2 반복문으로 2차원 리스트의 요소를 모두 출력하기

23.2.1 for반복문을 한 번만 사용하기

  • for x, y in a:와 같이 in 앞에 변수를 두 개 지정해주면 가로 한 줄(안쪽 리스트)에서 요소 두 개를 꺼낸다.
  • in 앞에 변수의 개수는 2차원 리스트에서 가로 크기(안쪽 리스트의 요소 개수)와 일치해야 한다.
  • 2차원 리스트의 가로 크기가 크지 않을 때 유용
>>> a = [[10, 20], [30, 40], [50, 60]]
>>> for x, y in a:    # 리스트의 가로 한 줄(안쪽 리스트)에서 요소 두 개를 꺼냄
         print(x, y)
# 실행결과
10 20
30 40
50 60

23.2.2 for 반복문을 두 번 사용하기

  • 먼저 for i in a:는 전체 리스트에서 가로 한 줄씩 꺼낸다.(안쪽 리스트를 통째로 꺼내 옴)
  • 다시 for j in i:와 같이 가로 한 줄(안쪽 리스트) i에서 요소를 하나씩 꺼낸다.
a = [[10, 20], [30, 40], [50, 60]]
 
for i in a:        # a에서 안쪽 리스트를 꺼냄
    for j in i:    # 안쪽 리스트에서 요소를 하나씩 꺼냄
        print(j, end=' ')
    print()
# 실행결과
10 20
30 40
50 60

23.2.3 for와 range 사용하기

  • for range에 세로 크기와 가로 크기를 넣으면 인덱스로 사용 가능
  • 주의할 점 : len으로 2차원 리스트 a의 크기를 구하면 리스트 안에 들어있는 모든 요소의 개수가 아니라 안쪽 리스트의 개수(세로 크기)가 나온다.
  • len으로 안쪽 리스트 a[i]의 크기를 구해야 안쪽 리스트에 들어있는 요소의 개수(가로 크기)가 나온다.
  • 요소에 접근할 때는 리스트[세로인덱스][가로인덱스] 형식
a = [[10, 20], [30, 40], [50, 60]]
 
for i in range(len(a)):            # 세로 크기
    for j in range(len(a[i])):     # 가로 크기
        print(a[i][j], end=' ')
    print()
# 실행결과
10 20 
30 40 
50 60
for i in range(len(a)):            # 세로 크기
    for j in range(len(a[i])):     # 가로 크기

23.2.4 while 반복문을 한 번 사용하기

  • 여기서 len(a)도 2차원 리스트의 크기를 구했으니 안쪽 리스트의 개수(세로 크기)가 나온다.
a = [[10, 20], [30, 40], [50, 60]]
 
i = 0
while i < len(a):    # 반복할 때 리스트의 크기 활용(세로 크기)
    x, y = a[i]      # 요소 두 개를 한꺼번에 가져오기
    print(x, y)
    i += 1           # 인덱스를 1 증가시킴
# 실행결과
10 20
30 40
50 60

23.2.5 while 반복문을 두 번 사용하기

  • 먼저 while i < len(a):와 같이 세로 크기만큼 반복하면서
  • while j < len(a[i]):와 같이 가로 크기(안쪽 리스트의 요소 개수, len(a[i]))만큼 반복
a = [[10, 20], [30, 40], [50, 60]]
 
i = 0
while i < len(a):         # 세로 크기
    j = 0
    while j < len(a[i]):    # 가로 크기
        print(a[i][j], end=' ')
        j += 1            # 가로 인덱스를 1 증가시킴
    print()
    i += 1                # 세로 인덱스를 1 증가시킴
# 실행결과
10 20 
30 40 
50 60
  • i += 1을 안쪽 while에서 수행하면 반복이 제대로 되지 않으므로 주의🔎
i = 0
while i < len(a):
    j = 0
    while j < len(a[i]):
        print(a[i][j], end=' ')
        j += 1
        i += 1    # 안쪽 while에서 i를 증가시키면 안 됨. 잘못된 방법
    print()

23.3 반복문으로 리스트 만들기

23.3.1 for 반복문으로 1차원 리스트 만들기

  • for반복문으로 10번 반복하면서 append로 요소를 추가
a = []    # 빈 리스트 생성
 
for i in range(10):
    a.append(0)    # append로 요소 추가
 
print(a)
# 실행결과
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

23.3.2 for 반복문으로 2차원 리스트 만들기

a = []    # 빈 리스트 생성
 
for i in range(3):
    line = []              # 안쪽 리스트로 사용할 빈 리스트 생성
    for j in range(2):
        line.append(0)     # 안쪽 리스트에 0 추가
    a.append(line)         # 전체 리스트에 안쪽 리스트를 추가
 
print(a)
# 실행결과
[[0, 0], [0, 0], [0, 0]]

23.3.3 리스트 표현식으로 2차원 리스트 만들기

  • 리스트 표현식을 활용하면 코드 한 줄로 2차원 리스트를 만들 수 있다.
  • 리스트 표현식 안에서 리스트 표현식 사용
  • [0 for j in range(2)]로 0을 2번 반복하여 [0, 0]으로 만들고
  • for i in range(3)으로 [0, 0]을 3번 반복하여 [[0, 0], [0, 0], [0, 0]]으로 만든다.
>>> a = [[0 for j in range(2)] for i in range(3)]
>>> a
[[0, 0], [0, 0], [0, 0]]
  • for반복문을 한 번만 사용 : 식 부분에서 리스트 자체를 곱해주면 된다.
>>> a = [[0] * 2 for i in range(3)]
>>> a
[[0, 0], [0, 0], [0, 0]]

23.3.4 톱니형 리스트 만들기

  • 가로 크기를 알고 있을 경우
    • 먼저 리스트 a에 톱니형 리스트의 가로 크기를 미리 저장
    • 리스트 a를 for로 반복하면 가로 크기를 꺼내면서 반복
    • for반복문 안에서 다시 for로 꺼낸 가로 크기 i만큼 반복하면서 append로 요소 추가
    • 바깥쪽 반복문에서 리스트 b에 안쪽 리스트 line을 추가
a = [3, 1, 3, 2, 5]    # 가로 크기를 저장한 리스트
b = []    # 빈 리스트 생성
 
for i in a:      # 가로 크기를 저장한 리스트로 반복
    line = []    # 안쪽 리스트로 사용할 빈 리스트 생성
    for j in range(i):    # 리스트 a에 저장된 가로 크기만큼 반복
        line.append(0)
    b.append(line)        # 리스트 b에 안쪽 리스트를 추가
 
print(b)
# 실행결과
[[0, 0, 0], [0], [0, 0, 0], [0, 0], [0, 0, 0, 0, 0]]
  • 리스트 표현식 활용
>>> a = [[0] * i for i in [3, 1, 3, 2, 5]]
>>> a
[[0, 0, 0], [0], [0, 0, 0], [0, 0], [0, 0, 0, 0, 0]]

📎 참조) sorted로 2차원 리스트 정렬하기
2차원 리스트를 정렬할 때는 sorted 함수를 사용

  • sorted(반복가능한객체, key=정렬함수, reverse=True 또는 False)
students = [
    ['john', 'C', 19],
    ['maria', 'A', 25],
    ['andrew', 'B', 7]
]
print(sorted(students, key=lambda student: student[1]))  # 안쪽 리스트의 인덱스 1을 기준으로 정렬
print(sorted(students, key=lambda student: student[2]))  # 안쪽 리스트의 인덱스 2를 기준으로 정렬
# 실행결과
[['maria', 'A', 25], ['andrew', 'B', 7], ['john', 'C', 19]]
[['andrew', 'B', 7], ['john', 'C', 19], ['maria', 'A', 25]]
  • student[1]은 안쪽 리스트의 인덱스 1을 뜻하며 'A', 'B', 'C' 순으로 정렬
  • student[2]는 안쪽 리스트의 인덱스 2를 뜻하며 7, 19, 25 순으로 정렬

📎참고)풀잎스쿨 진행 중 남철님 추가 예제 부분

# 기본 문법
print(sorted(순회가능한 객체, key= 함수))
# 순회가능한 객체(iterable) : list, tuple 등.
# 함수 : 정렬 기준
# 작동 순서
1. 함수에 순회가능한 객체의 요소들을 차례로 인자로 전달한다.
2. 전달받은 인자를 사용하여 반환받은 값들을 기준으로 '오름차순' 정렬한다.
3. 정렬한 순서로 순회가능한 객체의 요소를 리스트로 반환한다.)
>> str_list = ['좋은하루','good_morning','굿모닝','niceday']
>> print(sorted(str_list, key=len))  # 함수
['굿모닝', '좋은하루', 'niceday', 'good_morning']
# 풀이
1. len 함수에 str_list 의 요소들을 차례로 인자로 전달한다.
len('좋은하루') -> len('good_morning') -> len('굿모닝') -> len('niceday')
2. 전달받은 인자를 사용하여 반환받은 값들을 기준으로 오름차순 정렬한다.
반환값들 : 4 ,  12 , 3 , 7 
오름차순 정렬 : 3, 4, 7, 12
반환 하는 리스트 : ['굿모닝', '좋은하루', 'niceday', 'good_morning']
람다 예)
>> str_list = ['좋은하루','good_morning','굿모닝','niceday']
>> print(sorted(str_list, key=lambda x : x[1]))  
['niceday', 'good_morning', '굿모닝', '좋은하루']
#풀이 # lambda 매개변수 : 표현식
1. lambda x : x[1] 함수에 str_list 의 요소들을 차례로 인자로 전달한다.
x = '좋은하루' -> x = 'good_morning' -> x = '굿모닝' -> x = 'niceday'
2. 전달받은 인자를 사용하여 반환받은 값들을 기준으로 오름차순 정렬한다.
반환값(표현식): x[1] : '은', x[1] : 'o' , x[1] : '모', x[1] : 'i'
오름차순 정렬 : 'i' , 'o', '모', '은'
반환하는 리스트 :  ['niceday', 'good_morning', '굿모닝', '좋은하루']

23.4 2차원 리스트의 할당과 복사 알아보기

  • '22.2 리스트의 할당과 복사'에서 리스트를 다른 변수에 할당해도 변수 이름만 달라질 뿐 같은 리스트(객체)임을 확인했다.
  • 2차원 리스트도 마찬가지
  • 리스트 a를 copy 메서드로 b에 복사한 뒤 b의 요소를 변경해보면 리스트 a와 b에 모두 반영
>>> a = [[10, 20], [30, 40]]
>>> b = a
>>> b[0][0] = 500
>>> a
[[500, 20], [30, 40]]
>>> b
[[500, 20], [30, 40]]

>>> a = [[10, 20], [30, 40]]
>>> b = a.copy()
>>> b[0][0] = 500
>>> a
[[500, 20], [30, 40]]  # 리스트 a에도 반영
>>> b
[[500, 20], [30, 40]]  # 객체는 서로 다르다.🔎

  • 2차원 이상의 다차원 리스트는 리스트를 완전히 복사하려면 copy 메서드 대신 copy 모듈의 deepcopy 함수를 사용
  • copy.deepcopy 함수 : 중첩된 리스트(튜플)에 들어있는 모든 리스트(튜플)를 복사하는 깊은 복사(deep copy)를 해준다.
>>> a = [[10, 20], [30, 40]]
>>> import copy             # copy 모듈을 가져옴
>>> b = copy.deepcopy(a)    # copy.deepcopy 함수를 사용하여 깊은 복사
>>> b[0][0] = 500
>>> a
[[10, 20], [30, 40]]
>>> b
[[500, 20], [30, 40]]

23.5 연습문제: 3차원 리스트 만들기

다음 소스 코드를 완성하여 높이 2, 세로 크기 4, 가로 크기 3인 3차원 리스트를 만드세요(리스트 표현식 사용).

a = [_____________________]
 
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]]]
# 정답
[[[0 for col in range(3)] for row in range(4)] for depth in range(2)]

3차원 리스트의 형태

  • 리스트 = [[[값, 값], [값, 값]], [[값, 값], [값, 값]], [[값, 값], [값, 값]]]
  • 리스트[높이인덱스][세로인덱스][가로인덱스]
  • 리스트[높이인덱스][세로인덱스][가로인덱스] = 값

즉, 가로×세로 평면(2차원 리스트)이 여러 겹 있는 모양
따라서 한 면을 완성한 뒤 다른 면을 완성하는 방식으로 작성
리스트 표현식으로 세로 4, 가로 3인 2차원 리스트를 만들기

[[0 for col in range(3)] for row in range(4)]

여러 번 반복해주면 3차원 리스트가 된다.
여기서는 높이가 2라고 했으므로 for depth in range(2)와 같이 반복
이때 2차원 리스트가 다시 안쪽 리스트가 될 수 있도록 [ ]로 묶어준다.

[[[0 for col in range(3)] for row in range(4)] for depth in range(2)]
profile
안녕하세요 :-) 잘 부탁드립니다!

0개의 댓글