리스트 컴프리헨션은 기본 사용법뿐만 아니라 다중 루프도 지원한다.
아래는 행렬을 모든 셀이 포함된 평평한 리스트로 간략화 한다고 할 때, for 표현식 두 개를 사용한 리스트 컴프리헨션이다.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [x for row in matrix for x in row]
print(flat)
>>>
[1, 2, 3, 4, 5, 6, 7, 8, 9]
이 표현식은 __왼쪽에서 오른쪽 순서__로 실행된다.
다중 루프의 또 다른 합당한 사용법은 __입력 리스트의 레이아웃을 두 레벨로 중복__해서 구성하는 것이다.
예를 들어 2차원의 행렬에 각 셀에 있는 값의 제곱근은 두한다고 할 때 아래와 같이 표현할 수 있다.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
squared = [[x**2 for x in row] for row in matrix]
print(squared)
>>>
[[1, 4, 9], [16, 25, 36], [49, 64, 81]]
레이아웃을 중복해서 구성하기위해 추가로 [] 문자를 사용하였다.
처음 예제와는 달리 셀을 평평한 리스트로 만든 것이 아니다.
이 표현식을 다른 루프에 넣는다면 리스트 컴프리헨션이 여러 줄로 구분할 정도로 길어진다.
my_lists = [
[[1, 2, 3], [4, 5, 6]],
# ...
]
flat = [x for sublist1 in my_lists
for sublist2 in sublist1
for x in sublist2]
print(flat)
>>>
[1, 2, 3, 4, 5, 6]
이제 여러 줄짜리 컴프리헨션이 다른 방법보다 많이 짧지는 않다.
일반 루프문으로 같은 결과를 만들어보자.
my_lists = [
[[1, 2, 3], [4, 5, 6]],
# ...
]
flat = []
for sublist1 in my_lists:
for sublist2 in sublist1:
flat.extend(sublist2)
print(flat)
>>>
[1, 2, 3, 4, 5, 6]
큰 차이는 없지만 리스트 컴프리헨션보다 이해하기 쉽다.
리스트 컴프리헨션도 다중 if 조건을 지원하는데, 여러 조건이 있는 경우는 암시적으로 and 표현식이 된다.
예를 들어 리스트에서 4보다 큰 짝수만 구한다면 아래 두 컴프리헨션은 동일하다.
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b = [x for x in a if x > 4 if x % 2 == 0]
c = [x for x in a if x > 4 and x % 2 == 0]
조건은 루프의 각 레벨에서 for 표현식 뒤에 설정할 수 있다.
행렬에서 row의 합이 10 이상이고 3으로 나누어 떨어지는 셀을 구한다면 아래와 같이 표현할 수 있다.
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
filtered = [[x for x in row if x % 3 == 0]
for row in matrix if sum(row) >= 10]
print(filtered)
>>>
[[6], [9]]
이런 코드는 다른 사람들이 이해하기 매우 어렵다.
리스트 컴프리헨션을 사용할 때는 표현식이 두 개를 넘어가면 피하는 게 좋다.
이것보다 복잡해지면 if 문과 of for 문을 사용하고 헬퍼 함수를 사용해서 작성하도록한다.
*개인적으로 예제 수준은 크게 가독성이 떨어지는 것 같진 않다..*
더 복잡해지면 가독성이 떨어질 수 있기 때문에 for, if 또는 헬퍼 함수를 사용하자..
## 핵심 정리 1. 리스트 컴프리헨션은 다중 루프와 레벨별 다중 조건을 지원한다.
- 표현식이 두 개가 넘어가는 리스트 컴프리헨션은 가독성이 떨어지므로 피하자.