itertools는 파이썬에서 반복되는 데이터 = iterable한 데이터를 처리하는 기능을 포함하고 있는 라이브러리이다.
용어 설명
iterable 객체 : for문 와일문을 돌릴 수 있는 리스트같은 애들
iterator : 이터레이터는 이터러블한 객체에 내장함수 iter를 사용한 애들을 얘기한다. next 함수 호출 시 계속 그 다음 값을 리턴해주는 기능이 생긴다!
이터레이터는 한번 호출되면 다시 그 값을 읽을 수 없다는 특징이 있다.
그래서 for문을 이용하여 한번 반복하고 난 후에는 다시 반복하더라도 더 이상 그 값을 다시 가져오지 못한다. 객체를 이터레이터로 만들때는 조심하자!
이터레이터는 제한적인 제너레이터라고 보면 될 것 같다.
즉, 이터툴즈는 이터러블한 데이터를 이터레이터 형식으로 처리하는데 도움을 주는 모듈이라고 할 수 있겠다.
itertools.cycle(iterable) : iterable한 객체(ex. list)를 순서대로 무한히 반복시키는 이터레이터를 생성하는 함수. 앞서 next나 for문으로 추출한 값은 다시 생기지 않는다고 말했었지만 이 함수를 쓰면 계속 생긴다!
>>> import itertools
name = ['스파이더맨', '와스프', '벌쳐']
>>> infi = itertools.cycle(name)
>>> next(infi)
'스파이더맨'
>>> next(infi)
'와스프'
>>> next(infi)
'벌쳐'
>>> next(infi)
'스파이더맨'
>>> next(infi)
'와스프'
itertools.accumulate(iterable) : 이 함수는 iterable 객체의 누적합을 계산하여 이터레이터 형태로 리턴해주는 함수다. 누적 합계를 표시하고 싶을 때 아주 유용하다.
import itertools
m_income = [1161, 1814, 1270, 2256, 1413, 1842, 2221, 2207, 2450, 2823, 2540, 2134]
result = list(itertools.accumulate(m_income))
print(result)
[1161, 2975, 4245, 6501, 7914, 9756, 11977, 14184, 16634, 19457, 21997, 24131]
만약 1월에서 12월 기간 동안 월 수입의 최댓값을 누적하여 보여주고 싶다면 다음처럼 itertools.accumulate 함수의 두번째 인수로 max를 전달하여 구할 수 있다.
마찬가지로 최소값은 min을 전달하면 된다!
import itertools
m_income = [1161, 1814, 1270, 2256, 1413, 1842, 2221, 2207, 2450, 2823, 2540, 2134]
result = list(itertools.accumulate(m_income, max))
print(result) # 10월 최고 기록이 깨지지 않는 것을 볼 수 있다.
[1161, 1814, 1814, 2256, 2256, 2256, 2256, 2256, 2450, 2823, 2823, 2823]
permutations(list, r) : 리스트와 같은 itertable 객체에서 r개의 데이터를 뽑아 일렬로 나열하는 모든 경우(순서도 포함)을 계산해준다.
permutations는 클래스 형이므로 사용할때 리스트 자료형으로 한번 묶어주어야 한다.
리스트 ['A', 'B', 'C']에서 3개의 엘리먼트(r=3)를 뽑아 나열하는 모든 경우를 출력하는 예시는 다음과 같다.
from itertools import permutations
data = ['A', 'B', 'C'] # 데이터
result = list(permutations(data, 3)) # 가능한 모든 순열 구하기
print(result)
[('A', 'B', 'C'), ('A', 'C', 'B'), \\
('B', 'A', 'C'), ('B', 'C', 'A'), ('C', 'A', 'B'), ('C', 'B', 'A')]
모든 경우의 수를 다 나열해주어서 좋다. 만약 순서 상관없이 3개 2개를 고르는 경우의 수를 알고자 한다면 아래의 combinations 툴을 사용할 수 있다.
combinations(list, r) : 리스트와 같은 iterable 객체에서 r개를 선택할 수 있는 조합을 이터레이터로 리턴하는 함수다.
리스트 ['A', 'B', 'C']에서 2개(r=2)를 뽑아 짝을 맞춰서 출력하는 예시는 다음과 같다.
from itertools import combinations
data = ['A', 'B', 'C'] #데이터 준비
result = list(combinations(data, 2))
# 2개를 뽑는 모든 조합 구하기
print(result)
[('A', 'B'), ('A', 'C'), ('B', 'C')]
순서를 따지지 않으므로 경우의 수는 6개 -> 3개가 된다.
45개의 숫자 중에 6개를 뽑아 만들 수 있는 경우의 수!
>>> import itertools
>>> it = itertools.combinations(range(1, 46), 6)
근데 경우의 수가 엄청 길어지면 무한루프에 걸린다.
>>> for num in it:
... print(num)
...
(1, 2, 3, 4, 5, 6)
(1, 2, 3, 4, 5, 7)
(1, 2, 3, 4, 5, 8)
(1, 2, 3, 4, 5, 9)
(1, 2, 3, 4, 5, 10)
(1, 2, 3, 4, 5, 11)
(1, 2, 3, 4, 5, 12)
(1, 2, 3, 4, 5, 13)
...
한개만 출력하거나 적당히 끊어준다.
a = len(list(itertools.combinations(range(1, 46), 6)))
print(a)
8145060
복권에 당첨되기란 힘든 일이다.
combinations_with_replacement : combinations와 같이 리스트와 같은 iterable 객체에서 r개의 데이터를 뽑아 순서를 고려하지 않고 나열하는 모든 경우(조합)를 계산한다.
다만 원소를 중복해서 뽑는다.
예를 들면 [1,1,1,1,1,1] 처럼 숫자를 중복해서 쓸 수 있다면 경우의 수는 훨씬 더 많이 늘어날 것이다.
아까 복권의 예시를 들어보자.
from itertools import combinations_with_replacement
a = len(list(itertools.combinations_with_replacement(range(1, 46), 6)))
print(a)
15890700
리스트 ['A', 'B', 'C']에서의 예
from itertools import combinations_with_replacement
data = ['A', 'B', 'C']
result = list(combinations_with_replacement(data, 2))
print(result)
[('A', 'A'), ('A', 'B'), ('A', 'C'), \\
('B', 'B'), ('B', 'C'), ('C', 'C')]
product(list, repeat = r) : permutations에서 중복까지 더한 함수다.
product 객체를 초기화 할 때는 뽑고자 하는 데이터의 수를 repeat 속성값으로 넣어준다.
product는 클래스이므로 객체 초기화 이후에는 리스트 자료형으로 변환하여 사용한다. (콤비네이션도 다 그렇지만)
리스트 ['A', 'B', 'C']에서 중복을 포함하여 2개(r = 2)를 뽑아 나열하는 모든 경우의 수를 출력하는 예시는 다음과 같다.
from itertools import product
data = ['A', 'B', 'C']
result = list(product(data, repeat = 2))
# 2개를 뽑는 모든 순열 구하기 (중복 허용)
print(result)
[('A', 'A'), ('A', 'B'), ('A', 'C'), \\
('B', 'A'), ('B', 'B'), ('B', 'C'), \\
('C', 'A'), ('C', 'B'), ('C', 'C')]
자주 쓰는 걸 여기 놔뒀다가 기억하러 오자!
itertools.zip_longest(list1, list2, fillvalue='a') :
zip처럼 리스트 두개를 묶어주는데 길이가 긴 것 기준으로 빈 값에 설정된 데이터도 같이 묶어주는 편한 함수이다!
import itertools
students = ['a', 'b', 'c', 'd', 'e']
rewards = ['사탕', '초코', '젤리']
result = itertools.zip_longest(students, rewards, fillvalue='조청유과')
print(list(result))
[('a', '사탕'), ('b', '초코'), ('c', '젤리'), \\
('d', '조청유과'), ('e', '조청유과')]