count, cycle, repeat는 스스로 끝나지 않아. islice, 조건, 유한 소비자처럼 멈추는 장치와 함께 써야 해.
이어 붙이고 길이를 맞추고 일부만 고르기
chain은 여러 반복값을 하나로 잇고, zip_longest는 짧은 쪽의 빈자리를 채우며, islice는 리스트를 만들지 않고 구간만 소비해.
groupby는 붙어 있는 값만 묶는다
groupby는 같은 키가 연속될 때만 한 그룹으로 묶어. SQL처럼 같은 키를 모두 합치려면 먼저 그 키로 정렬해야 해. 각 그룹도 원본 반복자를 공유하므로 필요할 때 바로 소비해.
조합과 복제
product는 데카르트 곱, permutations는 순서 있는 배열, combinations는 순서 없는 선택을 만들어. tee는 한 반복자를 여러 갈래로 나누지만 갈래의 속도가 다르면 내부 저장량이 커질 수 있어.
Code
무한 반복자에 끝 조건 붙이기·python
import itertools as it
# count — range 인데 무한
for n in it.count(10, 2):
if n > 20:
break
print(n) # 10 12 14 16 18 20
# cycle — 라운드로빈
colors = it.cycle(["red", "green", "blue"])
for _ in range(7):
print(next(colors))
# red green blue red green blue red
# repeat — 제한 또는 무한
print(list(it.repeat("x", 4))) # ['x', 'x', 'x', 'x']
# 무한 zip + 유한 list
pairs = list(zip(it.count(1), ["a", "b", "c"]))
print(pairs) # [(1, 'a'), (2, 'b'), (3, 'c')]
chain·zip_longest·islice로 흐름 바꾸기·python
import itertools as it
# chain — iterable 이어붙임
result = list(it.chain([1, 2], [3, 4], [5]))
print(result) # [1, 2, 3, 4, 5]
# zip_longest — 가장 짧은 거에서 안 멈춤
result = list(it.zip_longest([1, 2, 3], ["a", "b"], fillvalue="?"))
print(result) # [(1, 'a'), (2, 'b'), (3, '?')]
# islice — *모든* iterable 슬라이싱, 무한 포함
def naturals():
n = 1
while True:
yield n
n += 1
first_5 = list(it.islice(naturals(), 5))
print(first_5) # [1, 2, 3, 4, 5]
연속된 키만 묶는 groupby·python
import itertools as it
items = ["apple", "ant", "banana", "berry", "apricot"]
# 순진한 groupby — 연속 매치만 그룹
for key, group in it.groupby(items, key=lambda x: x[0]):
print(key, list(group))
# a ['apple', 'ant']
# b ['banana', 'berry']
# a ['apricot'] <- 두 번째 'a' 그룹, 합쳐지지 *않음*
# SQL 스타일 그룹핑은 정렬 먼저
items.sort(key=lambda x: x[0])
for key, group in it.groupby(items, key=lambda x: x[0]):
print(key, list(group))
# a ['apple', 'ant', 'apricot']
# b ['banana', 'berry']
곱·순열·조합 만들기·python
import itertools as it
# product — 데카르트 곱 (nested for 루프 대체)
for x, y in it.product([1, 2], ["a", "b"]):
print(x, y)
# 1 a
# 1 b
# 2 a
# 2 b
# permutations — 모든 순서 있는 배치
print(list(it.permutations("abc", 2)))
# [('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')]
# combinations — 순서 없는 선택
print(list(it.combinations("abc", 2)))
# [('a', 'b'), ('a', 'c'), ('b', 'c')]
# combinations_with_replacement — 재사용 가능한 선택
print(list(it.combinations_with_replacement("ab", 2)))
# [('a', 'a'), ('a', 'b'), ('b', 'b')]
한 반복자를 여러 갈래로 나누는 tee·python
import itertools as it
source = (x*x for x in range(5))
a, b, c = it.tee(source, 3)
print(list(a)) # [0, 1, 4, 9, 16]
print(list(b)) # [0, 1, 4, 9, 16]
print(list(c)) # [0, 1, 4, 9, 16]
# 주의 — tee() 후에는 원본 source를 다시 쓰지 마
# tee 버퍼에 들어감
# 대부분 경우 list 로 materialize 하는 게 더 명확
squares = [x*x for x in range(5)]