본문 바로가기
<개인공부> - IT/[Python]

List comprehension

by Aggies '19 2020. 3. 30.
반응형
Overview

  파이썬에서 List comprehension의 정의는 list를 간결한 방법으로 생성하는 것을 의미한다. 아래와 같은 dev_info의 문자열로 구성된 data를 list로 만들고자 하는데 list comprehension 기능을 사용하지 않으면 두 줄 정도의 코드가 필요하다. 반대로 list comprehension을 이용한다면 한 줄로 표현할 수 있다. List를 생성함과 동시에 값을 할당하는 것이다. 

# [List comprehension 미사용]
dev_info = '    1.1.1.1,  username,  password    '
item_list = []
for elem in dev_info.split(','):
  item_list.append(elem.strip())
  
# [List comprehension 사용]
item_list = [elem.strip() for elem in dev_info.split(',')]

위에서 보는 것처럼 list comprehension 문법의 구조는 다음과 같다.

 

[ 할당될 값 for 변수이름 in 순회가 가능한 값 ]

 

가장 뒤에서 부터 하나씩 살표보자.

  1) dev_info.split(',') -> ['    1.1.1.1', '  username', '  password    '] 이 값이 담김.

  2) for문을 통해 각 elem에 접근하면 '    1.1.1.1', '  username', '  password    ' 각각의 값이 return 된다.

  3) 마지막으로 할당될 값인 elem.strip()은 각 요소의 공백을 삭제 후 item_list에 저장하는 과정을 진행한다.

 

순회가 가능한 값이라는 의미는 iterable 한 값이다. 결론은 list만 가능한 것이 아니고 range처럼 값을 하나씩 살펴볼 수 있는 것 부터 dict, set, tuple 모두 가능하다. 즉, for문에서 반복문을 수행하기 위해서 사용했던 모든 iterable 변수는 모두 사용가능하다는 의미이다. 개인적으로는 알고는 있지만 여전히 익숙하지 않아서 잘 사용하지 않는 문법이지만 최근 py.checkio.org에서 해당 문법을 활용해서 문제를 풀 기회가 생겨서 어렵사리 한번 이용해보았다. 

 

주어진 문자열 내에서 숫자가 있다면 그 합을 반환하는 함수를 작성하는 문제다.

예를 들면, hi는 0, who is 1st here도 역시 0 그리고 my number is 2는 2처럼 숫자와 문자가 합쳐있는 경우는 숫자로 인식하지 않고 단일 숫자만 있을 경우 그 합을 구하는 것이다.

sum([int(elem) for elem in text.split(' ') if elem.isdigit()])

앞서 설펴본 문법 구조에서 if문이 추가된 것을 볼 수 있다. 앞서 살펴본 예제에서는 list comprehension으로 생성하는 리스트는 순회가 가능한 값과 동일한 크기로 생성되는 것을 볼 수 있었는데 if문을 이용하면 값의 일부를 필터링 할 수 있게 된다.

 

[예제]

sum_numbers('hi') == 0
sum_numbers('who is 1st here') == 0
sum_numbers('my numbers is 2') == 2
sum_numbers('This picture is an oil on canvas painting by Danish artist Anna Petersen between 1845 and 1910 year') == 3755
sum_numbers('5 plus 6 is') == 11
sum_numbers('') == 0

 

내가 생각한 로직은 문장을 단어로 쪼개서 쪼개진 단어가 숫자인지를 확인후 그 값을 더하는 과정이다.

my numbers is 2를 생각해보면 text.split(' ') 구문을 통해서 ['my', 'numbers', 'is', '2']로 생성된 값을 if elem.isdigit()으로 숫자만 필터링 하여 가장 좌측 elem을 int로 형 변환해서 합을 구한다. 즉, 기본 list comprehension 문법에 if문을 통해서 filtering 기능을 추가하면 특정 값들을 필터링 할 수 있다는 점.

 

한 가지 더 재미있는 부분이지만 (개인적으로 복잡해서 거의 써본 적이 없는) 조건문을 중첩해서 사용할 수 있다. 1부터 30까지의 순회가능한 값에서 3의 배수이자 5의 배수인 값을 추리려면 어떻게 해야할까? 3으로 나눠서 나머지가 0인 경우와 5로 나눠서 나머지가 0인 경우를 and 조건으로 묶어주면 된다. 즉, 아래와 같이 if 문을 중첩하면 된다. 한 가지 알아두어야 할 점은 두 if 문을 and를 명시적으로 써주면 SyntaxError가 난다. (and를 이용해 연결하는것이 보다 좋은 가독성인 것 같은데...)

new_arr = [x for x in range(1, 30) if x % 3 == 0 if x % 5 == 0]

 

Usecase
  1. 리스트 안에 0을 찾아 그 index만 리스트로 만드는 방법
donuts = [100, 10, 0, 101, 1000]
index = [i for i, elem in enumerate(donuts) if elem == 0]

Reference site: https://py.checkio.org/en/mission/sum-numbers/

반응형