파이썬 Itertools 함수는 무엇입니까?

파이썬 Itertools 모듈 완벽 분석: 반복 작업의 효율성 극대화

파이썬 공식 문서에 따르면, itertools 모듈은 파이썬 반복자(iterator)를 다루기 위한 빠르고 메모리 효율적인 도구 모음입니다. 이 도구들은 개별적으로 또는 조합하여 사용할 수 있어, 반복자를 생성하고 조작하는 과정을 간결하고 효율적으로 만들어줍니다.

itertools 모듈은 특히 대량의 데이터 세트를 처리할 때 반복자를 사용한 작업을 훨씬 편리하게 만들어주는 여러 기능을 포함하고 있습니다. 이 모듈의 함수들은 기존 반복자를 기반으로 작동하며, 이를 통해 더욱 복잡한 파이썬 반복자를 만들 수 있도록 돕습니다.

또한 itertools는 개발자들이 반복자를 사용하여 작업할 때 발생할 수 있는 오류를 줄이고, 코드를 더욱 명확하고 가독성이 높게 유지할 수 있도록 지원하여 유지보수성을 높이는 데 기여합니다.

itertools 모듈의 반복자는 제공하는 기능에 따라 다음과 같이 세 가지 주요 유형으로 분류할 수 있습니다.

#1. 무한 반복자

무한 시퀀스를 다루거나, 루프를 종료하는 특정 조건 없이 무한 루프를 실행해야 할 때 사용되는 반복자입니다. 이러한 반복자는 무한 루프를 모방하거나 무한 시퀀스를 생성할 때 유용합니다. itertools 모듈에는 count(), cycle(), repeat()의 세 가지 무한 반복자가 있습니다.

#2. 조합 반복자

조합 반복자는 데카르트 곱 연산을 수행하고, 반복 가능한 객체(iterable)에 포함된 요소들의 조합 및 순열을 생성하는 데 사용되는 함수들로 구성됩니다. 이 함수들은 이터러블에서 요소들을 배열하거나 결합하는 모든 가능한 방법을 찾을 때 매우 유용합니다. itertools 모듈에는 product(), permutations(), combinations(), combinations_with_replacement() 네 가지 조합 반복자가 포함되어 있습니다.

#3. 가장 짧은 입력 시퀀스에서 종료되는 반복기

이 유형의 반복자는 유한 시퀀스에서 사용되며, 사용된 함수의 종류에 따라 결과를 생성합니다. 이러한 종료 반복자의 예시로는 accumulate(), chain(), compress(), dropwhile(), filterfalse(), groupby(), islice(), pairwise(), starmap(), takewhile(), tee(), zip_longest() 등이 있습니다.

이제 각 유형에 속하는 itertools 함수들이 어떻게 작동하는지 자세히 살펴보겠습니다.

무한 반복자 상세 분석

무한 반복자는 다음과 같은 세 가지 함수로 구성됩니다.

#1. count()

count(start, step) 함수는 지정된 시작 값(start)부터 시작하여 무한한 숫자 시퀀스를 생성합니다. 이 함수는 두 개의 선택적 인자인 startstep을 사용합니다. start 인수는 숫자 시퀀스가 시작될 값을 설정합니다. 만약 start 값이 제공되지 않으면 기본값으로 0부터 시작합니다. step 인수는 각 연속되는 숫자 간의 차이를 설정합니다. step의 기본값은 1입니다.

import itertools
# 4부터 시작하여 2씩 증가하는 숫자 생성
for i in itertools.count(4, 2):
    # 무한 루프를 방지하기 위한 종료 조건
    if i == 14:
        break
    else:
        print(i) # 출력 결과: 4, 6, 8, 10, 12

출력:

4
6
8
10
12

#2. cycle()

cycle(iterable) 함수는 이터러블을 인수로 받아, 이터러블의 항목들을 순환하면서 각 항목에 접근할 수 있도록 합니다.

예를 들어, ["red", "green", "yellow"] 리스트를 cycle()에 전달하면, 첫 번째 순환에서는 “red”에 접근하게 됩니다. 두 번째 순환에서는 “green”, 세 번째 순환에서는 “yellow”에 접근할 수 있습니다. 네 번째 순환에서는 이터러블의 모든 요소가 소진되었으므로 다시 “red”부터 시작하여 무한히 반복됩니다.

cycle()을 호출할 때 결과를 변수에 저장하여 상태를 유지하는 반복자를 생성하는 것이 중요합니다. 이렇게 하면 매번 처음부터 다시 시작하지 않고 반복자의 현재 상태를 유지할 수 있습니다.

import itertools

colors = ["red", "green", "yellow"]
# cycle() 함수에 colors 리스트 전달
color_cycle = itertools.cycle(colors)
print(color_cycle)

# 무한 루프를 7번 출력 후 종료
# next() 함수를 사용하여 반복자로부터 다음 항목을 가져옴
for i in range(7):
    print(next(color_cycle))

출력:

red
green
yellow
red
green
yellow
red

#3. repeat()

repeat(elem, n) 함수는 두 개의 인수를 받습니다. 첫 번째 인수는 반복할 요소(elem)이고, 두 번째 인수는 요소를 반복할 횟수(n)입니다. 반복할 요소는 단일 값이거나 이터러블일 수 있습니다. n이 전달되지 않으면 요소는 무한히 반복됩니다.

import itertools
   
for i in itertools.repeat(10, 3):
    print(i)

출력:

10
10
10

조합 반복자 상세 분석

조합 반복자는 다음의 함수들을 포함합니다.

#1. product()

product() 함수는 전달된 이터러블의 데카르트 곱을 계산하는 데 사용됩니다. 예를 들어, x = {7, 8}y = {1, 2, 3} 두 개의 이터러블 또는 집합이 있는 경우, x와 y의 데카르트 곱은 x와 y의 모든 가능한 요소 조합을 포함합니다. 이때 첫 번째 요소는 x에서 가져오고, 두 번째 요소는 y에서 가져옵니다. 이 경우 x와 y의 데카르트 곱은 [(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)]이 됩니다.

product() 함수는 이터러블의 데카르트 곱을 자체적으로 계산하는 데 사용되는 repeat이라는 선택적 매개변수를 사용합니다. repeat 매개변수는 데카르트 곱을 계산할 때 입력 이터러블의 각 요소에 대한 반복 횟수를 지정합니다.

예를 들어, product('ABCD', repeat=2)를 호출하면 ('A', 'A'), ('A', 'B'), ('A', 'C')와 같은 조합이 생성됩니다. repeat이 3으로 설정된 경우 함수는 ('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'A', 'C'), ('A', 'A', 'D')와 같은 조합을 생성합니다.

from itertools import product
# 선택적 repeat 인수를 사용한 product()
print("선택적 repeat 인수를 사용한 product() ")
print(list(product('ABC', repeat = 2)))

# repeat 인수 없이 product()
print("선택적 repeat 인수 없이 product()")
print(list(product([7,8], [1,2,3])))

출력:

선택적 repeat 인수를 사용한 product()
[('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')]
선택적 repeat 인수 없이 product()
[(7, 1), (7, 2), (7, 3), (8, 1), (8, 2), (8, 3)]

#2. permutations()

permutations(iterable, group_size) 함수는 전달된 이터러블의 가능한 모든 순열을 반환합니다. 순열은 집합의 요소를 정렬할 수 있는 방법의 수를 나타냅니다. permutations() 함수는 선택적 인자인 group_size를 사용합니다. group_size가 지정되지 않은 경우 생성된 순열의 크기는 함수에 전달된 이터러블의 길이와 동일합니다.

import itertools
numbers = [1, 2, 3]
sized_permutations = list(itertools.permutations(numbers,2))
unsized_permuatations = list(itertools.permutations(numbers))

print("크기가 2인 순열")
print(sized_permutations)
print("크기 인수 없이 순열")
print(unsized_permuatations)

출력:

크기가 2인 순열
[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
크기 인수 없이 순열
[(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)]

#3. combinations()

combinations(iterable, size) 함수는 함수에 전달된 이터러블의 요소로부터 주어진 크기(size)의 이터러블의 모든 가능한 조합을 반환합니다. size 인수는 각 조합의 크기를 지정합니다.

결과는 정렬됩니다. 조합은 순열과 약간 다릅니다. 순열에서는 순서가 중요하지만 조합에서는 순서가 중요하지 않습니다. 예를 들어 [A, B, C]의 경우 AB, AC, BA, BC, CA, CB의 6가지 순열이 있지만 AB, AC, BC의 세 가지 조합만 있습니다.

import itertools
numbers = [1, 2, 3,4]
size2_combination = list(itertools.combinations(numbers,2))
size3_combination = list(itertools.combinations(numbers, 3))

print("크기가 2인 조합")
print(size2_combination)
print("크기가 3인 조합")
print(size3_combination)

출력:

크기가 2인 조합
[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]
크기가 3인 조합
[(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]

#4. combinations_with_replacement()

combinations_with_replacement(iterable, size) 함수는 함수에 전달된 이터러블에서 주어진 크기(size)의 이터러블의 모든 가능한 조합을 생성하고, 출력 조합에서 반복되는 요소를 허용합니다. size는 생성된 조합의 크기를 결정합니다.

이 함수는 요소가 두 번 이상 반복될 수 있는 조합을 제공한다는 점에서 combinations() 함수와 다릅니다. 예를 들어, combinations()로는 얻을 수 없는 (1, 1)과 같은 조합을 얻을 수 있습니다.

import itertools
numbers = [1, 2, 3,4]

size2_combination = list(itertools.combinations_with_replacement(numbers,2))
print("combinations_with_replacement => 크기 2")
print(size2_combination)

출력:

combinations_with_replacement => 크기 2
[(1, 1), (1, 2), (1, 3), (1, 4), (2, 2), (2, 3), (2, 4), (3, 3), (3, 4), (4, 4)]

반복자 종료 상세 분석

이 유형의 반복자에는 다음이 포함됩니다.

#1. accumulate()

accumulate(iterable, function) 함수는 이터러블과 함수인 두 번째 선택적 인수를 받습니다. 그런 다음 이터러블의 각 요소에 대해 함수를 적용한 누적 결과를 반환합니다. 전달된 함수가 없으면 덧셈이 수행되고 누적된 결과가 반환됩니다.

import itertools
import operator
numbers = [1, 2, 3, 4, 5]

# 숫자의 합계 누적
accumulated_val = itertools.accumulate(numbers)
accumulated_mul = itertools.accumulate(numbers, operator.mul)
print("함수 없이 누적")
print(list(accumulated_val))
print("곱셈으로 누적")
print(list(accumulated_mul))

출력:

함수 없이 누적
[1, 3, 6, 10, 15]
곱셈으로 누적
[1, 2, 6, 24, 120]

#2. chain()

chain(iterable_1, iterable_2, ...) 함수는 여러 이터러블을 받아 이들을 연결하여 chain() 함수에 전달된 이터러블의 모든 값을 포함하는 단일 이터러블을 생성합니다.

import itertools

letters = ['A', 'B', 'C', 'D']
numbers = [1, 2, 3]
colors = ['red', 'green', 'yellow']

# letters, numbers, colors 연결
chained_iterable = list(itertools.chain(letters, numbers, colors))
print(chained_iterable)

출력:

['A', 'B', 'C', 'D', 1, 2, 3, 'red', 'green', 'yellow']

#3. chain.from_iterable()

chain.from_iterable(iterable) 함수는 chain()과 유사하게 작동합니다. 하지만 하위 이터러블을 포함하는 단일 이터러블만 받아 함께 연결한다는 점에서 chain()과 다릅니다.

import itertools

letters = ['A', 'B', 'C', 'D']
numbers = [1, 2, 3]
colors = ['red', 'green', 'yellow']

iterable = ['hello',colors, letters, numbers]
chain = list(itertools.chain.from_iterable(iterable))
print(chain)

출력:

['h', 'e', 'l', 'l', 'o', 'red', 'green', 'yellow', 'A', 'B', 'C', 'D', 1, 2, 3]

#4. compress()

compress(data, selectors) 함수는 이터러블인 data와 부울 값(TrueFalse)을 포함하는 이터러블인 selectors의 두 가지 인수를 받습니다. 1과 0은 부울 값 TrueFalse에 대한 대안으로 사용할 수도 있습니다. compress() 함수는 선택기에 전달된 해당 요소를 사용하여 전달된 데이터를 필터링합니다.

선택기의 값이 True 또는 1에 해당하는 데이터의 값은 선택되고, False 또는 0에 해당하는 나머지 값은 무시됩니다. 데이터의 항목 수보다 선택기에 더 적은 수의 부울 값을 전달하면, 선택기에 전달된 부울 이외의 모든 요소가 무시됩니다.

import itertools

# data에는 10개의 항목이 있음
data = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
# 9개의 선택기 항목 전달
selectors = [True, False, 1, False, 0, 1, True, False, 1]

# 선택기에 기반하여 데이터에서 요소 선택
filtered_data = list(itertools.compress(data, selectors))
print(filtered_data)

출력:

['A', 'C', 'F', 'G', 'I']

#5. dropwhile()

dropwhile(function, sequence) 함수는 True 또는 False를 반환하는 조건과 값의 시퀀스를 포함하는 함수를 받습니다. 그런 다음 전달된 조건이 False를 반환할 때까지 모든 값을 삭제합니다. 조건이 False를 반환하면 True 또는 False를 반환하는지 여부에 관계없이 나머지 요소가 결과에 포함됩니다.

import itertools

numbers = [1, 2, 3, 4, 5, 1, 6, 7, 2, 1, 8, 9, 0, 7]

# 전달된 조건이 False가 될 때까지 요소 삭제
filtered_numbers = list(itertools.dropwhile(lambda x: x < 5, numbers))
print(filtered_numbers)

출력:

[5, 1, 6, 7, 2, 1, 8, 9, 0, 7]

#6. filterfalse()

filterfalse(function, sequence) 함수는 True 또는 False로 평가되는 조건과 시퀀스를 포함하는 함수를 받습니다. 그런 다음 함수의 조건을 만족하지 않는 시퀀스의 값을 반환합니다.

import itertools

numbers = [1, 2, 3, 4, 2, 3, 5, 6, 5, 8, 1, 2, 3, 6, 2, 7, 4, 3]

# 조건이 False인 요소 필터링
filtered_numbers = list(itertools.filterfalse(lambda x: x < 4, numbers))
print(filtered_numbers)

출력:

[4, 5, 6, 5, 8, 6, 7, 4]

#7. groupby()

groupby(iterable, key) 함수는 이터러블과 키를 받아, 연속 키와 그룹을 반환하는 반복자를 생성합니다. 제대로 작동하려면 전달된 이터러블이 동일한 키 함수에서 정렬되어야 합니다. 키 함수는 이터러블의 각 요소에 대한 키 값을 결정합니다.

import itertools

input_list = [("Domestic", "Cow"), ("Domestic", "Dog"), ("Domestic", "Cat"),("Wild", "Lion"), ("Wild", "Zebra"), ("Wild", "Elephant")]
classification = itertools.groupby(input_list,lambda x: x[0])
for key,value in classification:
    print(key,":",list(value))

출력:

Domestic : [('Domestic', 'Cow'), ('Domestic', 'Dog'), ('Domestic', 'Cat')]
Wild : [('Wild', 'Lion'), ('Wild', 'Zebra'), ('Wild', 'Elephant')]

#8. islice()

islice(iterable, start, stop, step) 함수를 사용하면 전달된 시작(start), 중지(stop) 및 단계(step) 값을 사용하여 이터러블을 슬라이스할 수 있습니다. step 인수는 선택 사항입니다. 카운트는 0부터 시작하며, 중지 번호의 항목은 결과에 포함되지 않습니다.

import itertools

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]

# 특정 범위 내의 요소 선택
selected_numbers = list(itertools.islice(numbers, 2, 10))
selected_numbers_step= list(itertools.islice(numbers, 2, 10,2))
print("step 값을 설정하지 않은 islice")
print(selected_numbers)
print("step 값이 2인 islice")
print(selected_numbers_step)

출력:

step 값을 설정하지 않은 islice
[3, 4, 5, 6, 7, 8, 9, 10]
step 값이 2인 islice
[3, 5, 7, 9]

#9. pairwise()

pairwise(iterable) 함수는 전달된 이터러블에서 나타나는 순서대로 연속적으로 겹치는 쌍을 반환합니다. 전달된 이터러블의 값이 2개 미만이면 pairwise()의 결과는 비어 있습니다.

from itertools import pairwise

numbers = [1, 2, 3, 4, 5, 6, 7, 8]
word = 'WORLD'
single = ['A']

print(list(pairwise(numbers)))
print(list(pairwise(word)))
print(list(pairwise(single)))

출력:

[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6), (6, 7), (7, 8)]
[('W', 'O'), ('O', 'R'), ('R', 'L'), ('L', 'D')]
[]

#10. starmap()

starmap(function, iterable) 함수는 인수 매개변수가 이미 튜플로 그룹화되어 있을 때 map() 함수 대신 사용되는 함수입니다. starmap() 함수는 전달된 이터러블의 요소에 함수를 적용합니다. 이터러블은 튜플로 그룹화된 요소를 가져야 합니다.

import itertools

iter_starmap = [(123, 63, 13), (5, 6, 52), (824, 51, 9), (26, 24, 16), (14, 15, 11)]
print (list(itertools.starmap(min, iter_starmap)))

출력:

[13, 5, 9, 16, 11]

#11. takewhile()

takewhile(function, iterable) 함수는 dropwhile()과 반대 방식으로 작동합니다. takewhile() 함수는 평가할 조건과 이터러블을 받는 함수를 인수로 사용합니다. 그런 다음 False가 반환될 때까지 함수의 조건을 만족하는 이터러블의 모든 요소를 ​​포함합니다. False가 반환되면 이터러블의 다음 요소는 모두 무시됩니다.

import itertools

numbers = [1, 2, 3, 4, 5, 1, 6, 7, 2, 1, 8, 9, 0, 7]

# 전달된 조건이 False가 될 때까지 요소 선택
filtered_numbers = list(itertools.takewhile(lambda x: x < 5, numbers))
print(filtered_numbers)

출력:

[1, 2, 3, 4]

#12. tee()

tee(iterable, n) 함수는 이터러블을 받아 여러 개의 독립적인 반복자를 반환합니다. 반환할 반복자의 수는 n으로 설정되며, 기본값은 2입니다.

import itertools

numbers = [1, 2, 3, 4, 5]

# numbers에서 두 개의 독립적인 반복자 생성
iter1, iter2 = itertools.tee(numbers, 2)
print(list(iter1))
print(list(iter2))

출력:

[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5]

#13. zip_longest()

zip_longest(iterables, fillvalue) 함수는 여러 이터러블과 하나의 채우기 값(fillvalue)을 받습니다. 그런 다음 전달된 각 이터러블에서 요소를 집계하는 반복자를 반환합니다. 이터러블의 길이가 같지 않은 경우, 누락된 값은 가장 긴 이터러블이 소진될 때까지 함수에 전달된 채우기 값으로 대체됩니다.

import itertools

names = ['John', 'mathew', 'mary', 'Alice', 'Bob', 'Charlie', 'Fury']
ages = [25, 30, 12, 13, 42]

# 이름과 나이를 결합하고, 누락된 나이는 대시로 채움
combined = itertools.zip_longest(names, ages, fillvalue="-")

for name, age in combined:
    print(name, age)

출력:

John 25
mathew 30
mary 12
Alice 13
Bob 42
Charlie -
Fury -

결론

파이썬의 itertools 모듈은 파이썬 개발자에게 매우 중요한 도구 세트입니다. itertools는 함수형 프로그래밍, 데이터 처리 및 변환, 데이터 필터링 및 선택, 그룹화 및 집계, 이터러블 결합, 조합, 무한 시퀀스를 다룰 때 광범위하게 활용됩니다.

파이썬 개발자로서 itertools에 대해 학습하는 것은 큰 도움이 될 수 있으므로, 이 기사를 통해 파이썬 Itertools를 익히는 데 도움이 되기를 바랍니다.