one of a kind scene

[Python] Comprehension에 대해서 본문

카테고리 없음

[Python] Comprehension에 대해서

specialscene 2020. 3. 26. 01:01
Comprehension

Comprehension

  • 리스트, 셋, 딕셔너리 를 쉽게 만드는 Comprehension에 대해서 공부하고자 함
  • Python에 기본 자료형으로는 튜플, 리스트, 셋, 딕셔너리가 있는데, 이 중에서 튜플만 Comprehension이 없음
  • 한국어로는 지능형 튜플, 지능형 리스트 등으로 표현하기도 한다

1) List Comprehension(LC)

1-1) 일반적인 LC

In [1]:
# 20까지의 짝수를 출력하기 위해 다음과 같은 LC를 사용할 수 있다
evens = [x * 2 for x in range(11)]
print(evens)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
In [2]:
# 리스트의 모든 원소값을 정규화 시킨 후 상수값을 더하는 LC
values = [32, 12, 96, 42, 32, 93, 31, 23, 65, 43, 76]
total = sum(values)
normalization = [(x / total) + 1 for x in values]
print(normalization)
[1.0587155963302752, 1.0220183486238532, 1.1761467889908257, 1.0770642201834861, 1.0587155963302752, 1.1706422018348623, 1.0568807339449542, 1.0422018348623854, 1.1192660550458715, 1.0788990825688074, 1.1394495412844037]

1-2) 좀 더 복잡한 LC

  • 1) if문(=조건)을 지닌 LC
  • 2) Nested LC
In [3]:
# if문을 활용하여 제곱근이 정수가 아닌 경우를 찾는 LC
from math import sqrt
non_squars = [x for x in range(101) if sqrt(x)**2 != x]
print(non_squars)
[2, 3, 5, 6, 7, 8, 10, 12, 13, 15, 18, 19, 20, 23, 24, 26, 28, 29, 31, 32, 37, 38, 40, 43, 45, 48, 50, 51, 52, 58, 59, 60, 61, 63, 65, 66, 72, 73, 75, 76, 77, 78, 80, 82, 87, 89, 92, 94, 95, 96, 97]
In [4]:
# 두 리스트의 원소들의 모든 조합을 찾는 LC
# 참고로 epithets는 별칭을 뜻함
epithets = ['sweet', 'annoying', 'cool', 'grey-eyed']
names = ['john', 'alice', 'james']
epithet_names = [(e, n) for e in epithets for n in names]
print(epithet_names)
[('sweet', 'john'), ('sweet', 'alice'), ('sweet', 'james'), ('annoying', 'john'), ('annoying', 'alice'), ('annoying', 'james'), ('cool', 'john'), ('cool', 'alice'), ('cool', 'james'), ('grey-eyed', 'john'), ('grey-eyed', 'alice'), ('grey-eyed', 'james')]

1-3) practical LC 예제

  • 1) 1~30까지 숫자중에 피타고라스 방정식의 해를 찾는 LC
  • 2) 단어에서 모음을 제거하는 LC
  • 3) Nested LC를 flatten하게 만드는 LC
In [5]:
# a^2 + b^2 = c^2 (a < b < c)를 만족하는 피타고라스 방정식의 해를 찾는 LC
solutions = [(x, y, z) for x in range(1, 30) for y in range(x, 30) for z in range(y, 30) if x**2 + y**2 == z**2]
print(solutions)
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (7, 24, 25), (8, 15, 17), (9, 12, 15), (10, 24, 26), (12, 16, 20), (15, 20, 25), (20, 21, 29)]
In [6]:
# 단어에서 모음을 제거하는 LC
word = 'mathematics'
without_vowels = ''.join([c for c in word if c not in ['a', 'e', 'i', 'o', 'u']])
print(without_vowels)
mthmtcs
In [7]:
# 행렬을 일차원화 시키는 LC
# matrix에서 한행씩 가져와서 행에 있는 value들을 가져옴
matrix = [
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9, 10, 11, 12],
]
flatten = [e for r in matrix for e in r]
print(flatten)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
In [ ]:
 

2) Set Comprehension(SC)

  • LC와 정확히 동일하며 단지 list가 아닌 set을 생성한다는 것만 다르다.
In [8]:
# 다음의 LC는 중복된 값들을 포함한다
no_primes = [j for i in range(2, 9) for j in range(i * 2, 50, i)]
print(no_primes)
[4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 10, 15, 20, 25, 30, 35, 40, 45, 12, 18, 24, 30, 36, 42, 48, 14, 21, 28, 35, 42, 49, 16, 24, 32, 40, 48]
In [9]:
# SC를 사용하면 중복값이 없는 집합을 얻을 수 있다
no_primes = {j for i in range(2, 9) for j in range(i * 2, 50, i)}
print(no_primes)
{4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45, 46, 48, 49}
In [ ]:
 

3) Dict Comprehension(DC)

  • LC와 동일하며 dict를 생성한다.
  • 1) 두 리스트를 하나의 dict로 합치는 DC
  • 2) 튜플로 구성된 리스트를 dict 형태로 변환하는 DC
In [10]:
# 두 리스트를 하나의 dict로 합치는 DC. 하나는 key, 또 다른 하나는 value로 사용한다
subjects = ['math', 'history', 'english', 'computer engineering']
scores = [90, 80, 95, 100]
score_dict = {key: value for key, value in zip(subjects, scores)}
print(score_dict)
{'math': 90, 'history': 80, 'english': 95, 'computer engineering': 100}
In [11]:
# 튜플 리스트를 dict 형태로 변환하는 DC
score_tuples = [('math', 90), ('history', 80), ('english', 95), ('computer engineering', 100)]
score_dict = {t[0]: t[1] for t in score_tuples}
print(score_dict)
{'math': 90, 'history': 80, 'english': 95, 'computer engineering': 100}
In [ ]:
 

(번외) Generator Expression (GE)

  • Generator expression은 특별한 형태의 comprehension
  • 한 번에 모든 원소를 반환하지 않고 한 번에 하나의 원소만 반환하는 generator를 생성
  • GE 또한 다른 Comprehension과 동일한 형태로 쉽게 사용할 수 있다.
In [12]:
# 다음 Generator는 제곱수를 만들어낸다
gen = (x**2 for x in range(10))
print(gen)
<generator object <genexpr> at 0x00000192516BB5E8>
In [13]:
print(next(gen)) # call 1
print(next(gen)) # call 2
print(next(gen)) # call 3
print(next(gen)) # call 4
print(next(gen)) # call 5
print(next(gen)) # call 6
print(next(gen)) # call 7
print(next(gen)) # call 8
print(next(gen)) # call 9
print(next(gen)) # call 10
# 여기까지 'next' 함수를 활용해서 호출을 10번 반복

# 11번째에서는 error가 발생
print(next(gen)) # call 11
0
1
4
9
16
25
36
49
64
81
---------------------------------------------------------------------------
StopIteration                             Traceback (most recent call last)
<ipython-input-13-1e767ac1096c> in <module>
     12 
     13 # 11번째에서는 error가 발생
---> 14 print(next(gen)) # call 11

StopIteration: 
In [14]:
# Yes, it is an just generator. You can sum the yielding values.
# GE로 생성한 Generator도 yield를 가진 함수로 생성한 것과 동일한 Generator이기 때문에, 
# 똑같이 sum을 사용할 수 있다. (iterable 객체)
gen = (x**2 for x in range(10))
sum_of_squares = sum(gen)
print(sum_of_squares)
285
In [ ]:
 
In [ ]:
 
In [ ]: