본문 바로가기

개발일지/TIL

TIL 23-04-27 팀원과의 코드리뷰 - 특별한 이차원 배열 1

1. 팀원과의 코드리뷰 - 특별한 이차원 배열 1

 문제점

문제 설명
정수 n이 매개변수로 주어질 때, 
다음과 같은 n × n 크기의 이차원 배열 arr를 return 하는 solution 함수를 작성해 주세요.

arr[i][j] (0 ≤ i, j < n)의 값은 i = j라면 1, 아니라면 0입니다.
제한사항
1 ≤ n ≤ 100
입출력 예
n   result
3   [[1, 0, 0], 
    [0, 1, 0], 
    [0, 0, 1]]
6   [[1, 0, 0, 0, 0, 0], 
    [0, 1, 0, 0, 0, 0], 
    [0, 0, 1, 0, 0, 0], 
    [0, 0, 0, 1, 0, 0], 
    [0, 0, 0, 0, 1, 0], 
    [0, 0, 0, 0, 0, 1]]
1   [[1]]

# n은 정수
 # return은 n*n의 이차원 배열
 # arr[i][j]의 값이 일치하는 부분의 원소는 1, 아니면 0

 시도해 본 것들

[[n만큼의 원소를 가진 리스트]를 n만큼 가진 리스트] 만들기 

a = ([[0]*n]*n) #[[0, 0, 0], [0, 0, 0], [0, 0, 0]]

 

[i] == [j]일 때 arr[i][j]의 원소 1로 만들기

for j, i in enumerate(a):
        print(f'변경전 값 {i, j}')
        i[j] = 1
        print(f'변경후 값 {i, j}')
        print()
        
변경전 값 ([0, 0, 0], 0)
변경후 값 ([1, 0, 0], 0)

변경전 값 ([1, 0, 0], 1)
변경후 값 ([1, 1, 0], 1)

변경전 값 ([1, 1, 0], 2)
변경후 값 ([1, 1, 1], 2)

return a # [[1, 1, 1], [1, 1, 1], [1, 1, 1]]

어째서인지 i[j]를 통해서 값을 변경하면 다른 리스트의 원소도 함께 영향을 받아서 결국 모든 원소가 1로 바뀜 

 

원소의 값이 같이 바뀌는 원인 찾기 

# 모두 같은 id를 가짐
    print(f'a[0]의 id : {id(a[0])}') #a[0]의 id : 2640066693120
    print(f'a[1]의 id : {id(a[1])}') #a[1]의 id : 2640066693120
    print(f'a[2]의 id : {id(a[2])}') #a[2]의 id : 2640066693120

[0]*n을 *n만큼 반복하는 이 과정이 문제였다.

[0]*n으로 만들어진 리스트를 새롭게 만드는 게 아닌 같은 id값을 가진 리스트를 얕은 복사로 가져오기 때문에 값만 같은 게 아닌 동일한 리스트가 n번 생성되어 모든 변경사항이 같이 반영되는 것이었다. 

 

다른 방법으로 2차원 배열 만들기

two_dimensional_array = [[0]*n for i in range(n)]  
#[[0, 0, 0], [0, 0, 0], [0, 0, 0]] = two_dimensional_array

test_array = [[0 for i in range(n)] for j in range(n)]  
#[[0, 0, 0], [0, 0, 0], [0, 0, 0]] = test_array

비슷한 코드로 만들었는데 하나는 *연산자를 사용했고 다른 하나는 for문을 두번 이용했다.

 

마찬가지로 각 리스트의 id 확인

    print(f'two_dimensional_array[0]의 id : {id(two_dimensional_array[0])}')
    # two_dimensional_array[0]의 id : 2640052989632
    print(f'two_dimensional_array[1]의 id : {id(two_dimensional_array[1])}')
    # two_dimensional_array[1]의 id : 2640066491264
    print(f'two_dimensional_array[2]의 id : {id(two_dimensional_array[2])}')
    # two_dimensional_array[2]의 id : 2640066612096
    
    print(f'test_array[0]의 id : {id(test_array[0])}')
    # test_array[0]의 id : 2640052979200
    print(f'test_array[1]의 id : {id(test_array[1])}')
    # test_array[1]의 id : 2640066695616
    print(f'test_array[2]의 id : {id(test_array[2])}')
    # test_array[2]의 id : 2640066614144

각각의 경우를 확인하면 id값이 모두 다른 것을 볼 수 있다. 

 

[i] == [j]일 때 arr[i][j]의 원소 1로 만들기 2

for j, i in enumerate(two_dimensional_array):
        print(f'변경전 값 {i, j}')
        i[j] = 1
        print(f'변경후 값 {i, j}')
        print()
        
변경전 값 ([0, 0, 0], 0)
변경후 값 ([1, 0, 0], 0)

변경전 값 ([0, 0, 0], 1)
변경후 값 ([0, 1, 0], 1)

변경전 값 ([0, 0, 0], 2)
변경후 값 ([0, 0, 1], 2)

return two_dimensional_array #[[1, 0, 0], [0, 1, 0], [0, 0, 1]]

각 리스트의 id가 달라지면서 원소를 조작했을 때 그 리스트의 원소만 바뀌는 것을 확인했다.

그리고 결과 값도 원하는 대로 잘 출력 되는 것을 알 수 있었다.

 

2중 for문을 이용한 풀이

for i in range(n):
        for j in range(n):
            print(j, i)
            if i == j:
                test_array[i][j] = 1
print(test_array) # [[1, 0, 0], [0, 1, 0], [0, 0, 1]]

0 0 # if문 진입
1 0
2 0
0 1
1 1 # if문 진입
2 1
0 2
1 2
2 2 # if문 진입

문제에서 제시한 것은 i==j일 때  1로 만들라는 조건이 있었기에 그 조건이 명확히 보이는 방법으로 2중 for문을 사용해서 풀었다.

 

다른 팀원의 코드 

def solution(n):
    answer = []
    for i in range(n):
        ainner = []
        for j in range(n): 
            if i == j:
                ainner.append(1)
            else:
                ainner.append(0)
        answer.append(ainner)
    return answer

이차원 배열의 생성을 위에서 부터 따라갔을 때 쉽게 이해되는 코드로 공부하는 단계에서 굉장히 좋은 코드 같다. 

 

def solution(n):
    answer=[]
    for i in range(n):
        inner_list=list(map(int,"0"*n))
        inner_list[i]=1
        answer.append(inner_list)
    return answer

위의 다른 팀원의 코드와 유사하면서 list(map(int,"0"*n))를 통해 for문을 하나 대체했다. 

 해결 방법

def solution(n):
    two_dimensional_array = [[0]*n for _ in range(n)]
    for j, i in enumerate(two_dimensional_array):
        i[j] = 1
    return two_dimensional_array

 알게 된 점

GPT한테 코드 비교해달라고 하지 말아야겠다. 알려준 시간복잡도와 공간복잡도가 이상해서 계속 물어보니 잘못 비교했다고 사과를 자꾸 듣는다.

import time
start_time = time.time()  # 측정 시작

# 프로그램 소스코드
end_time = time.time()  # 측정 종료
print("time:", end_time - start_time)  # 수행 시간 출력

GPT가 믿음직스럽지 못해서 찾아보니 시간복잡도를 직접 확인할 수 있는 코드가 존재했다.

이걸 통해서 내 눈으로 시간 복잡도를 직접 보는 게 좋을 것 같다.

[[0]*n]*n같은 방식으로 2차원 배열을 만들면 얕은 복사로 리스트가 생성되는 것을 알 수 있다.