파이썬3의 itertools

grouper 레시피


In [1]:
list(zip([1,2,3], ['a','b','c']))


Out[1]:
[(1, 'a'), (2, 'b'), (3, 'c')]

In [2]:
# iter() 함수는 iterator object를 리턴한다. 
iter([1,2,3,4])


Out[2]:
<list_iterator at 0x1053f85f8>

In [3]:
# map 함수는 싱글파라메터 함수를 각각의 엘리먼트에 한방에 적용가능
list(map(len, ['abc', 'de', 'fghi']))


Out[3]:
[3, 2, 4]

In [4]:
list(map(sum, zip([1,2,3], [4,5,6])))


Out[4]:
[5, 7, 9]

In [5]:
# 입력받은 리스트를 n개로 쪼개는 함수인데, n이 커지면 커질수록 메모리를 많이 쓰는 단점이 있다. 
def naive_grouper(inputs, n):
    num_groups = len(inputs) // n
    return [tuple(inputs[i*n:(i+1)*n]) for i in range(num_groups)]

In [6]:
nums = [1,2,3,4,5,6,7,8,9,10]
naive_grouper(nums, 2)


Out[6]:
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]

In [7]:
# itertools 를 사용해서 좀 더 나은 함수를 만들 수 있다. 

def better_grouper(inputs, n):
    iters = [iter(inputs)] * n
    return zip(*iters)

In [8]:
nums = [1,2,3,4,5,6,7,8,9,10]
# * 연산자는 n 개의  같은 이터레이터의 레퍼런스를 생성한다.
iters = [iter(nums)] * 2
list(id(itr) for itr in iters)


Out[8]:
[4384437584, 4384437584]

In [9]:
print(*iters)


<list_iterator object at 0x105553550> <list_iterator object at 0x105553550>

zip(*iters) 는 iters 안의 각 이터레이터를 돌면서 엘리먼트의 쌍으로 이루어진 이터레이터를 리턴한다.


In [10]:
list(better_grouper(nums, 2))


Out[10]:
[(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]

In [11]:
# 4개로 나눠서 쪼개면 뒤에 9,10 이 짤림
# zip 은 모자라는 녀석은 그냥 무시함
list(better_grouper(nums, 4))


Out[11]:
[(1, 2, 3, 4), (5, 6, 7, 8)]

In [12]:
# zip_longest 를 쓰면 짤리는 것도 iteration 가능
import itertools as it
x = [1,2,3,4,5]
y = ['a','b','c']
list(zip(x, y))


Out[12]:
[(1, 'a'), (2, 'b'), (3, 'c')]

In [13]:
list(it.zip_longest(x, y))


Out[13]:
[(1, 'a'), (2, 'b'), (3, 'c'), (4, None), (5, None)]

In [14]:
# better_grouper 를 수정한 grouper 메서드를 만들자

import itertools as it

def grouper(inputs, n):
    iters = [iter(inputs)] * n
    return it.zip_longest(*iters)

In [15]:
nums = [1,2,3,4,5,6,7,8,9,10]
list(grouper(nums, 4))


Out[15]:
[(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, None, None)]

brute force야 너도!

당신에게 20달러 지폐 3개, 10달러 지폐 5개, 5달러 지폐 2개, 1달러 지폐 5개 가 있다고 하자.

100달러를 만드는 방법은 몇가지나 있을까?

n개의 셋에서 k개를 골라내야하는 조합(combination) 문제이다. itertools.combination() 을 써봅시다.


In [16]:
import itertools as it

bills = [20, 20, 20, 10, 10, 10, 10, 10, 5, 5, 1, 1, 1, 1, 1]
list(it.combinations(bills,3 ))


Out[16]:
[(20, 20, 20),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 5),
 (20, 20, 5),
 (20, 20, 1),
 (20, 20, 1),
 (20, 20, 1),
 (20, 20, 1),
 (20, 20, 1),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 5),
 (20, 20, 5),
 (20, 20, 1),
 (20, 20, 1),
 (20, 20, 1),
 (20, 20, 1),
 (20, 20, 1),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 5, 5),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 10),
 (20, 20, 5),
 (20, 20, 5),
 (20, 20, 1),
 (20, 20, 1),
 (20, 20, 1),
 (20, 20, 1),
 (20, 20, 1),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 5, 5),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 10),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 10),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 5),
 (20, 10, 5),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 10, 1),
 (20, 5, 5),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 5, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (20, 1, 1),
 (10, 10, 10),
 (10, 10, 10),
 (10, 10, 10),
 (10, 10, 5),
 (10, 10, 5),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 10),
 (10, 10, 10),
 (10, 10, 5),
 (10, 10, 5),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 10),
 (10, 10, 5),
 (10, 10, 5),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 5),
 (10, 10, 5),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 5, 5),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 10, 10),
 (10, 10, 10),
 (10, 10, 5),
 (10, 10, 5),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 10),
 (10, 10, 5),
 (10, 10, 5),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 5),
 (10, 10, 5),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 5, 5),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 10, 10),
 (10, 10, 5),
 (10, 10, 5),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 5),
 (10, 10, 5),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 5, 5),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 10, 5),
 (10, 10, 5),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 10, 1),
 (10, 5, 5),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 5, 5),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 5, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (10, 1, 1),
 (5, 5, 1),
 (5, 5, 1),
 (5, 5, 1),
 (5, 5, 1),
 (5, 5, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (5, 1, 1),
 (1, 1, 1),
 (1, 1, 1),
 (1, 1, 1),
 (1, 1, 1),
 (1, 1, 1),
 (1, 1, 1),
 (1, 1, 1),
 (1, 1, 1),
 (1, 1, 1),
 (1, 1, 1)]

위의 문제를 풀려면 1개부터 len(bills) 까지 꺼내는 루프를 돌면서 그 합이 100인것을 찾으면 된다.


In [17]:
makes_100 = []
for n in range(1, len(bills) + 1 ):
    for combination in it.combinations(bills, n):
        if sum(combination) == 100:
            makes_100.append(combination)

set(makes_100)


Out[17]:
{(20, 20, 10, 10, 10, 10, 10, 5, 1, 1, 1, 1, 1),
 (20, 20, 10, 10, 10, 10, 10, 5, 5),
 (20, 20, 20, 10, 10, 10, 5, 1, 1, 1, 1, 1),
 (20, 20, 20, 10, 10, 10, 5, 5),
 (20, 20, 20, 10, 10, 10, 10)}

위의 결과를 보면 답은 5가지 인것을 알 수 있다.

문제를 조금 변경해보자.

50달러, 20달러, 10달러, 5달러, 1달러짜리를 가지고 100달러를 만드는 경우의 수는 몇가지가 있을까?


In [18]:
# 미리 정의된 셋이 없기때문에 만들어줘야 함. itertools_combinations_with_replacement() 함수를 쓰면 됨

list(it.combinations_with_replacement([1,2], 2))


Out[18]:
[(1, 1), (1, 2), (2, 2)]

In [19]:
# 50, 20, 10, 5, 1 로 만들수 있는 경우의 수를 다 만들면 됨 
# 1달러 100개면 100달러이므로 최대 길이를 100으로 하면 됨
bills = [50, 20, 10, 5, 1]
make_100 = []
for n in range(1, 101):
    for combination in it.combinations_with_replacement(bills, n):
        if sum(combination) == 100:
            make_100.append(combination)

In [20]:
len(make_100)


Out[20]:
343

In [21]:
# 순열도 가능 (permutation)
list(it.permutations(['a', 'b', 'c']))


Out[21]:
[('a', 'b', 'c'),
 ('a', 'c', 'b'),
 ('b', 'a', 'c'),
 ('b', 'c', 'a'),
 ('c', 'a', 'b'),
 ('c', 'b', 'a')]

Sequences of Numbers


In [22]:
def evens():
    n = 0
    while True:
        yield n
        n += 2
        
evens = evens()
list(next(evens) for _ in range(5))


Out[22]:
[0, 2, 4, 6, 8]

In [23]:
def odds():
    n = 1
    while True:
        yield n
        n += 2
odds = odds()
list(next(odds) for _ in range(5))


Out[23]:
[1, 3, 5, 7, 9]

In [24]:
counter = it.count()
list(next(counter) for _ in range(5))


Out[24]:
[0, 1, 2, 3, 4]

In [25]:
evens = it.count(step=2)
list(next(evens) for _ in range(5))


Out[25]:
[0, 2, 4, 6, 8]

In [26]:
odds = it.count(start=1, step=2)
list(next(odds) for _ in range(5))


Out[26]:
[1, 3, 5, 7, 9]

In [27]:
count_with_floats = it.count(start=0.5, step=0.75)
list(next(count_with_floats) for _ in range(5))


Out[27]:
[0.5, 1.25, 2.0, 2.75, 3.5]

In [28]:
negative_count = it.count(start=-1, step=0.5)
list(next(negative_count) for _ in range(5))


Out[28]:
[-1, -0.5, 0.0, 0.5, 1.0]

In [29]:
list(zip(it.count(), ['a', 'b', 'c']))


Out[29]:
[(0, 'a'), (1, 'b'), (2, 'c')]

Recurrence Relations (재귀 상태)


In [30]:
def fibs():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

In [31]:
def accumulate(inputs, func):
    itr = iter(inputs)
    prev = next(itr)
    for cur in itr:
        yield prev
        prev = func(prev, cur)

In [32]:
list(it.accumulate([1,2,3,4,5]))


Out[32]:
[1, 3, 6, 10, 15]

In [33]:
list(it.accumulate([9,21,17,5,11,12,2,6], min))


Out[33]:
[9, 9, 9, 5, 5, 5, 2, 2]

In [34]:
list(it.accumulate([1,2,3,4,5], lambda x ,y: (x + y) / 2))


Out[34]:
[1, 1.5, 2.25, 3.125, 4.0625]

In [35]:
list(it.accumulate([1,2,3,4,5], lambda x,y : x - y))


Out[35]:
[1, -1, -4, -8, -13]

In [36]:
list(it.accumulate([1,2,3,4,5], lambda x,y : y - x))


Out[36]:
[1, 1, 2, 2, 3]

In [37]:
def first_order(p, q, initial_val):
    return it.accumulate(it.repeat(initial_val), lambda s, _: p*s + q)

In [38]:
import itertools as it
it.count()


Out[38]:
count(0)

In [39]:
it.count(start=1, step=2)


Out[39]:
count(1, 2)

In [40]:
it.repeat(2)


Out[40]:
repeat(2)

In [41]:
it.repeat(2,5)


Out[41]:
repeat(2, 5)

In [ ]:
list(it.cycle(['a','b','c']))

In [ ]:
# 배열 곱하기
import itertools as it
list(it.product([1,2], ['a', 'b']))

In [ ]:
# itertools.tee 
iter1, iter2 = it.tee(['a', 'b', 'c'], 2)
list(iter1)

In [ ]:
list(iter2)

In [ ]:
list(it.islice([1,2,3,4], 3))

In [ ]:
list(it.islice([1,2,3,4], 1, 2))

In [ ]:
list(it.chain('abc', [1,2,3]))