파이썬 - 순열처리 itertools

HR.lee·2022년 2월 5일
0

itertools

itertools는 파이썬에서 반복되는 데이터 = iterable한 데이터를 처리하는 기능을 포함하고 있는 라이브러리이다.

용어 설명

iterable 객체 : for문 와일문을 돌릴 수 있는 리스트같은 애들

iterator : 이터레이터는 이터러블한 객체에 내장함수 iter를 사용한 애들을 얘기한다. next 함수 호출 시 계속 그 다음 값을 리턴해주는 기능이 생긴다!

이터레이터는 한번 호출되면 다시 그 값을 읽을 수 없다는 특징이 있다.
그래서 for문을 이용하여 한번 반복하고 난 후에는 다시 반복하더라도 더 이상 그 값을 다시 가져오지 못한다. 객체를 이터레이터로 만들때는 조심하자!

이터레이터는 제한적인 제너레이터라고 보면 될 것 같다.

즉, 이터툴즈는 이터러블한 데이터를 이터레이터 형식으로 처리하는데 도움을 주는 모듈이라고 할 수 있겠다.

실전 모듈 사용

itertools.cycle - 무한 반복자

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 - 누적합 계산

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 - 순열 = 중복없는, 정렬된, '모든' 가능한 경우

permutations(list, r) : 리스트와 같은 itertable 객체에서 r개의 데이터를 뽑아 일렬로 나열하는 모든 경우(순서도 포함)을 계산해준다.

  • 1, 2가 있다면 2, 1도 있다!

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 - 순열 = 중복없는, 가능한 경우

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_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 - 중복있는, 순서 뒤집은 것도 포함한 모든 가능한 경우

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

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', '조청유과')]
profile
It's an adventure time!

0개의 댓글