리스트를 쉽게 구현하는 방법을 배운다.
먼저 0부터 1억 사이의 모든 홀수를 항목으로 갖는 리스트를 구현하는 방법을 고민해보자. 가장 단순한 방법은 아래와 같이 홀수를 모두 나열하는 것이다.
[1, 3, 5, 7, 9, 11, ..., 99999999]
그런데 0부터 1억 사이의 총 5천만개의 홀수를 위와 같이 나열하는 것은 불가능하다. 1초에 하나씩 숫자를 적는다 해도 5천만 초, 약 1년 8개월이 걸린다.
이제 반복문을 이용해보자. 아래 함수는 0부터 입력된 숫자 사이의 모든 홀수를 항목으로 갖는 리스트를 리턴한다.
In [1]:
def odd_number(num):
L=[]
for i in range(num):
if i%2 == 1:
L.append(i)
return L
1억 까지의 홀수들의 리스트를 생성하는 걸리는 시간을 확인해보자.
In [2]:
%time odd_sample1 = odd_number(100000000)
지금 사용하는 컴퓨터에서는 13초 정도 걸린다. 사람이 사실상 할 수 없는 일을 컴퓨터는 10여초 만에 해결함을 알 수 있다.
처음 20개의 홀수를 확인해보자.
In [3]:
odd_sample1[:20]
Out[3]:
이제 질문을 좀 달리하자.
odd_number
함수를 좀 더 간결하게 정의할 수 없을까?
이에 대해 파이썬에서는 리스트 조건제시법이라는 기술을 제공한다. 이 기술을 모든 언어가 지원하지는 않으며, 지원하는 언어는 아래 사이트에서 확인할 수 있다.
https://en.wikipedia.org/wiki/List_comprehension
예를 들어, C# 언어는 from ... where ... select ...
가 비슷한 역할을 지원하지만 좀 다르고,
Java 언어에서는 함수 인터페이스를 이용하여 비슷한 기능을 구현할 수 있다.
리스트의 조건제시법을 이해하기 위해서는 집합 정의에 사용되는 조건제시법을 이해하면 된다.
0부터 1억 사이의 홀수들의 집합을 여러 방식으로 표현할 수 있다.
원소 나열법
{1, 2, 3, ...., 99999999}
조건제시법 1
{x | 0 <= x < 1억, 단 x는 홀수}
조건제시법 2
{2 * y + 1 | 0 <= y < 50000000}
앞서 언급했든 여기서도 원소나열법은 중략기호(...
)를 사용하기 전에는 사실상 사용 불가능하다. 반면에 조건제시법 1과 2는 어느 누구가 의미를 이해할 수 있다. 리스트 조건제시법은 위에 사용된 조건제시법과 거의 모양이 비슷하다. 다만 프로그래밍 언어를 사용할 뿐이다.
먼저 조건제시법 1을 파이썬 코드로 옮기면 다음과 같다.
In [4]:
odd_number1 = [x for x in range(100000000) if x % 2 == 1]
위 코드에서 아래 부분이 핵심이다.
x for x in range(100000000) if x % 2 == 1
위 코드를 집합기호 대신 리스트 기호로 감싸기만 하면 리스트 원하는 리스트를 만들어준다.
for
는 집합 정의에서 왼쪽과 오른쪽을 구분하는 짝대기('|') 역할을 한다.
if
는 만족해야 하는 조건을 의미하는 '단' 역할을 한다.
x % 2 == 1
는 홀수 여부를 물으며 참일 경우에만 사용된다는 것을 의미한다.
리스트 조건제시법을 사용하지 않으려면 다음고 같이 할 수 있다.
In [5]:
odd_number1 = []
for x in range(100000000):
if x % 2 == 1:
odd_number1.append(x)
else:
pass
odd_number1[:20]
Out[5]:
이제 조건제시법 2를 구현해보자.
In [6]:
odd_number2 = [2 * y + 1 for y in range(50000000)]
이 방식은 좀 더 쉬워 보인다. if
문이 없기 때문이다.
이렇게 기존의 리스트를 이용하여 새로운 리스트를 새롭게 만들 수 있다.
조건제시법을 사용하지 않는 방법은 아래와 같다.
In [7]:
odd_number2 = []
for x in range(50000000):
odd_number2.append(2*x+1)
odd_number2[:20]
Out[7]:
In [8]:
import math
In [9]:
[math.exp(n) for n in range(11)]
Out[9]:
좀 더 복잡하게 사용해되 된다.
In [10]:
[math.exp(3*n) for n in range(11)]
Out[10]:
In [11]:
words = 'The quick brown for jumps \
over the lazy dog'.split()
words
Out[11]:
위 words
리스트의 각 항목의 문자열들을 모두 대문자와 소문자로 바꾼 단어와 그리고 해당 항목의 문자열의 길이를 항목으로 갖는 리스트들의 리스트를 작성하고자 한다.
[['THE', 'the', 3], ['QUICK', 'quick', 5], ....]
반복문을 이용하여 아래와 같이 작성할 수 있다.
In [12]:
L =[]
for x in words:
L.append([x.upper(), x.lower(), len(x)])
L
Out[12]:
리스트 조건제시법으로는 아래와 같이 보다 간결하게 구현할 수 있다.
In [13]:
[[x.upper(), x.lower(), len(x)] for x in words]
Out[13]:
처음 두 단어만 다루고자 할 경우에는 아래처럼 하면 된다.
In [14]:
[[x.upper(), x.lower(), len(x)] for x in words[:2]]
Out[14]:
아래처럼 인덱스에 제한을 가하는 방식도 가능하다. 즉, if
문을 추가로 활용한다.
In [15]:
[[words[n].upper(), words[n].lower(), len(words[n])] \
for n in range(len(words)) if n < 2]
Out[15]: