내가 알고리즘 공부를 하면서 처음으로 이유를 검색해본 문제이자 여전히, 그리고 앞으로도 계속해서 사용할 리스트 컴프리헨션을 소개하고자 한다.

알고리즘 공부를 하다보면 새로운 입력을 받기 전에 먼저 비어있는 리스트를 생성해 빈 리스트에 입력값을 넣곤 한다.
이는 메모리의 할당 문제로서 "앞으로 여기에 얼마만큼의 메모리가 사용될 예정이니 비워놔!"라는 예약의 개념이라고 보면 좋을 듯하다. 만약 메모리를 할당해놓지 않으면, 우리도 모여서 앉아있다가 한 명이 추가로 와서 자리를 내려고 하면 옆에 앉아있던 사람들이 모두 일어나서 옆으로 움직이는 작업을 하는데 오랜 시간이 걸리고 복잡하듯이 계산 시에도 미리 메모리를 할당해놓지 않고 데이터를 새롭게 추가한다면, 새롭게 메모리를 할당하고 데이터를 입력해야하므로 그만큼의 연산 시간이 낭비된다. 특히나 연산의 수가 늘어날수록 해당 작업으로 인한 시간 소요가 상당하다.
그렇기에 제한된 시간 내에 연산해야하는 테스트에서의 메모리 할당은 필수적이다. 그러나 반대로 만약 메모리를 중요시하는 작업이라면, 사용되지 않는 비어있는 리스트를 우선 할당하고 사용하므로 메모리측면에서는 비효율적이라고 볼 수 있다.

그런데 왜 간단한 연산자를 놔두고 for 문을 사용하는 비교적 복잡한 방법을 선택할까?
나또한 처음 공부하며 더 간단한 방법이라고 생각하고 * 연산자를 이용해서 2차원 리스트를 생성했었다.

lst = [[0]*5]*5

print(lst)
>> lst = [[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]]

위와같이위와 같이 단순히 *연산자만을 가지고 메모리를 할당하면 매우 간단하고 직관적이며 빠르다. 하지만 이렇게 만들어진 2차원 리스트는 사용할 수 없다. 흔히 접하는 문제로 위와 같이 비어있는 리스트를 만들고 특정 위치에 값을 입력하면 다음과 같이 작동한다.

lst[1][2] = 9

print(lst)
>> lst = [[0,0,9,0,0],[0,0,9,0,0],[0,0,9,0,0],[0,0,9,0,0],[0,0,9,0,0]]

나는 분명히 2번째 리스트의 3번째 원소만 9 로 입력했는데 왜 모든 리스트의 3번째 원소가 9로 바뀐 것인가?

또 반대로 2차원 리스트가 아닌 1차원 리스트를 위 방법으로 만들 땐 전혀 문제없이 입력 및 출력이 된다.

lst = [0]*5
lst[2] = 9

print(lst)
>> lst = [0,0,9,0,0]

왜 1차원 리스트에서는 문제가 없지만 2차원 리스트 이상으로 올라가면 이상한 문제가 발생할까?
1차원 리스트 작성 시에는 리스트 안에 0 이라는 최소 단위 객체를 5개 곱하는것으로 각각 다른 객체가 할당된다. 하지만 2차원 리스트 작성시에는 0이라는 최소단위 객체가 5 개 들어있는 A라는 객체가 또다시 5 개 곱해져서 [A,A,A,A,A] 와 같이 큰 리스트 B 안에 A라는 같은 객체가 5개 할당되는 것이다. 따라서 만약 2번째 A 의 3번째 0 원소를 바꾼다 한들, A라는 객체의 3번째 0이라는 원소를 9 로 바꾸고 그 A 라는 동일한 객체가 B안에 5개 위치하므로, 위와 같이 입출력이 이루어진다.

이와 같은 문제를 해결해주며, 또한 여러 가지 부가기능을 갖추고 있는 것이 리스트컴프리헨션이다.
흔히 for 문을 작성할 땐 : (콜론) 이후에 원하는 동작을 입력하지만, 리스트컴프리헨션은 : (콜론) 없이 앞에 작성한다

lst = [x for x in range(10) if x%2 == 1]
#위의 코드와

lst = []
for x in range(10):
	if x%2 == 1:
    	lst.append(x)
# 위의 코드는 똑같이 작동한다. 하지만 첫번째 리스트 컴프리헨션이 더욱 간결하고 빠르게 작동한다

위와 같이 리스트 안에 for 문을 작성하는 것을 리스트 컴프리헨션이라고 하며 해당 방법을 통해 리스트 메모리를 할당한다면 앞서 발생했던 원치 않는 입출력을 방지할 수 있다.

lst = [[0]*5 for _ in range(5)]

lst[0][2] = 999

print(lst)
>> lst = [[0,0,999,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0],[0,0,0,0,0]]

알고리즘 테스트 문제를 풀다 보면 생각보다 리스트 자료형을 정말 많이 사용한다.(나만 그런 건지도 모르지만)
그러다 보면 별에 별 리스트에 의한 문제들에 직면한다. 하지만 리스트 컴프리헨션을 통해 다른 것보다 단순히 * 연산자만 사용한다면 같은 객체로 인식하여 오류(컴퓨터 입장에선 오류가 아니지만)가 발생하는 점만 알고 가면 좋을 듯하다.

 

문제들 하나하나 다 처리하기엔 저의 지식도 너무 짧고 시간도 오래 걸립니다. 그래서 제가 틀리고서 혹은 알게 되고서 감명을 받거나 정리해두면 좋겠다 싶은 내용을 정리해서 올립니다. 여전히 공부 중이고 여전히 지식이 많이 짧습니다. 이후에 글이 수정될 여지도 많습니다. 적어도 이 글을 적는 현재 제가 이해하고 있는 부분까지 만을 정리해서 적는 공간입니다. 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기