Python - List Comprehension(리스트 표현식)
List Comprehensions : 리스트 표현식
리스트 표현식은 리스트를 만드는 간결한 방식을 제공합니다.
비교 : 리스트 표현식과 기존의 방식들
예제 : 0~10의 제곱수를 담은 squares라는 리스트를 만들어보자.
<기존 방식1 : claasic>
squares = []
for x in range(10):
squares.append(x**2)
문제점 : x라는 변수가 loop 이후에도 존재.
<기존 방식2: 위 문제점 해결>
squares = list(map(lambda x: x**2, range(10)))
<리스트 표현식>
squares = [x**2 for x in range(10)]
방식2와 비교하였을 때, 보다 간결하고 가독성이 뛰어나다는 것을 알 수 있습니다.
리스트 표현식(listcomp)는 expression과 뒤에 따라오는 for문, 그 뒤에 따라오는n개의 for나 if문을 포함한 brackets(대괄호[])로 구성되어있습니다.
listcomp의 구성 (for문과 if문의 배치)에 대해 예시를 통해 알아보겠습니다.
(listcomp의 구성(문법)을 말로써 설명하기 쉽지 않습니다.)
>>> vec = [-4, -2, 0, 2, 4]
>>> # 요소 *2인 새로운 list 생성
>>> [x*2 for x in vec]
[-8, -4, 0, 4, 8]
>>> # 음수를 필터링합니다.
>>> [x for x in vec if x >= 0]
[0, 2, 4]
>>> # 함수를 적용합니다. 아래에서 vec은 여전히 [-4, -2, 0, 2, 4]입니다.
>>> [abs(x) for x in vec]
[4, 2, 0, 2, 4]
>>> # 각 요소에서 해당 객체의 method를 호출합니다.
>>> # 아래 예제에서는 str.strip()함수를 호출하여 앞뒤 공백을 제거하도록 하였습니다.
>>> freshfruit = [' banana', ' loganberry ', 'passion fruit ']
>>> [weapon.strip() for weapon in freshfruit]
['banana', 'loganberry', 'passion fruit']
>>> # (숫자, 제곱결과) 형태의 튜플을 가지고 있는 리스트를 생성합니다.
>>> [(x, x**2) for x in range(6)]
[(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
>>> # 위와 같이 튜플을 안에 넣고 싶을 때, 반드시 튜플의 원소들은 괄호로 쌓여있어야합니다.
>>> [x, x**2 for x in range(6)]
File "<stdin>", line 1, in <module>
[x, x**2 for x in range(6)]
^
SyntaxError: invalid syntax
>>> # 차원을 줄입니다.
>>> # 아래 listcomp는 다음과 같이 해석하면 쉽습니다.
>>> # 1. vec에 있는 요소들을 elem으로 하나씩 꺼내오고,
>>> # 2. 이 elem에 있는 요소들을 num으로 하나씩 꺼내온다.
>>> # 3. 이 num을 expression으로하여 결과에 적용한다.
>>> # 4. 즉, listcomp에서의 for문은 앞에서 뒤로 이해되는 것을 알 수 있습니다.
>>> vec = [[1,2,3], [4,5,6], [7,8,9]]
>>> [num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> # 1이 포함되지 않은 리스트를 대상으로 차원을 줄입니다.
>>> [num for elem in vec if 1 not in elem for num in elem]
# or [num for elem in vec for num in elem if 1 not in elem] : 동일한 효과를 냅니다.
[4, 5, 6, 7, 8, 9]
>>> # 1을 제외하고 차원을 줄입니다.
>>> [num for elem in vec for num in elem if num!=1]
# [num for elem in vec if num!=1 for num in elem ] : 에러가 발생합니다. num이 아직 정의되지 않았기 때문입니다.
[2, 3, 4, 5, 6, 7, 8, 9]
listcomp의 expr, for, if의 구성에 대해 예제를 통해 정리해보겠습니다.
>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
이 예시는 다음과 동일합니다.
>>> combs = []
>>> for x in [1,2,3]:
... for y in [3,1,4]:
... if x != y:
... combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
이 둘의 공통점은 for문의 순서와 if문의 순서가 동일하다는 것입니다.
따라서, [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]은
각 for, if가 차례로 하위 코드블록을 이루며 구성되어있고, 가장 안쪽의 코드블록에 .append((x,y))가 있음을 확인할 수 있습니다.
[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
# ^1 ^2 ^3 ^4
# ^1 : 최하위(i=0) 코드블록
# ^2 : 최상위(i=n) 코드블록
# ^3 : i = n-1의 코드블록
# ^4 : i = n-1(=0+1)의 코드블록
#2~4까지 layer를 이루며 이전의 것의 하위 코드블록을 구성하며, 최하위 코드블록으로 ^1이 들어간다.
cobs = []
for x in [1,2,3] : # 최상위 코드블록
for y in [3,1,4]: # 하위 1 코드블록
if x != y: # 하위 2 코드블록
combs.append((x,y)) # 최하위 코드블록
listcomp의 결과는 listcomp안의 for, if문들의 맥락안에서 연산된 expression의 결과들로 이루어진 새로운 리스트입니다.
리스트 표현식 + 문자열 포메팅 + join()등 다양한 기능을 합친 최종 보스이다.
one -> five까지 5글자를 기준으로 c언어 배열로 초기화 할 수 있게하는 코드이다.
이거를 왜 만들었냐하면,, 하나하나 다 입력하기 귀찮았기 때문..
(물론 이 코드를 만드는데 더 많은 시간이 걸렸다. 하지만 나름 유익한 시간이었다)
print('{'+',\n'.join(['{'+f"""'{"','".join([j for j in i])}'"""+'}' for i in [i+'-'*(5-len(i)) for i in ['ZERO','ONE','TWO','THREE','FOUR','FIVE']]])+'}')