C.W.K.
Stream
Lesson 03 of 07 · published

itertools — Lazy 반복 도구상자

~25 min · itertools, chain, groupby, tee, product

Level 0호기심
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete

표준 라이브러리의 반복 초능력

iterator 와 generator 이해하면 itertools 가 표준 라이브러리에서 가장 유용한 모듈 중 하나. iterable 다루는 빠르고 메모리 효율적인 빌딩 블록 모음. 컴프리헨션처럼 list 만드는 게 아니라 — itertools 함수는 lazy iterator 반환. 파이프라인처럼 합성.

무한 삼총사 — count / cycle / repeat

count(start, step)start, start+step, ... 영원히. cycle(iter)iter 의 원소 계속 반복. repeat(value, times) — 같은 값, 옵션으로 정해진 횟수. 항상 *멈추는 뭔가* 와 페어 (islice, break, 유한 iterable 과의 zip) — 안 그러면 무한 루프.

chain / zip_longest / islice — 구조적인 것

chain(a, b, c)a 의 모든 원소, 그 다음 b, 그 다음 c. concat 의 lazy 버전. zip_longestzip 인데 가장 짧은 거에서 안 멈춤 — 채움 값으로 패딩. islice(iter, start, stop, step) 은 어떤 iterable 도 슬라이싱, 무한도 포함.

groupby — 모두를 놀라게 하는 놈

groupby(iter, key) 는 같은 키 공유하는 *연속* 원소를 그룹. 두 가지 알아야 — 오직 *연속* 원소만 그룹 (모든 그룹 같이 묶고 싶으면 정렬 먼저), yield 되는 그룹은 그 자체로 iterator 라 다음 가기 전에 소비해야 돼. 사람들은 SQL GROUP BY 처럼 동작 기대해 — 사실 Unix uniq 에 더 가까움.

tee — iterator 쪼개기

iterator 는 한 번만 소비 가능. tee(iter, n) 가 한 source 에서 n 개의 독립 iterator 만들어 — 내부적으로 필요 시 버퍼링. 아껴 써 — 한 가지가 다른 가지보다 너무 빨리 가면 버퍼 커져. 대부분 tee 손에 닿는 경우는 source 를 list 로 만드는 게 더 단순해.

product / permutations / combinations

조합론 삼총사. product(a, b) — 데카르트 곱, 모든 (x, y) 페어. permutations(iter, r) — 모든 순서 있는 r 길이 배치. combinations(iter, r) — 순서 없는 r 길이 선택. "~ 의 모든 조합" 류 문제의 nested for 루프 통째 대체.

Code

무한 iterator — 멈추는 뭔가와 페어·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']
product / permutations / combinations·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 — iterator 하나를 여러 개로·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 사용 X
# tee 버퍼에 들어감

# 대부분 경우 list 로 materialize 하는 게 더 명확
squares = [x*x for x in range(5)]

External links

Exercise

events = [{"user": "a", "action": "login"}, {"user": "a", "action": "click"}, {"user": "b", "action": "login"}, {"user": "b", "action": "logout"}, {"user": "a", "action": "logout"}]. itertools.groupby (적절한 정렬과 함께) 로 dict {user: [actions...]} 만들어. 그 다음 itertools.product 로 모든 (user, color) 페어 — colors 는 ["red", "green", "blue"]. 그 다음 islice + 무한 count()[10, 13, 16, 19, 22].

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.