Pynote

Python、機械学習、画像処理について

Python - itertools チートシート (頻出パターン)

概要

itertools モジュールを使用した頻出パターンを紹介する。

itertools の import

import itertools

等間隔の値を返すイテレータを作成する。

itertools.count(start=0, step=1)

初項だけ指定する。

for val in itertools.count(1):
    print(val, end=' ')
# 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ...

初項と公差を指定する。

for val in itertools.count(1, 2):
    print(val, end=' ')
# 1 3 5 7 9 11 13 15 17 19 ...

配列を無限に繰り返すイテレータを作成する。

itertools.cycle(iterable)

array = ['a', 'b', 'c']
for val in itertools.cycle(array):
    print(val, end=' ')
# a b c a b c a b c a b c a b c ...

同じ値を繰り返すイテレータを作成する。

[https://docs.python.jp/3/library/itertools.html#itertools.repeat:title=itertools.repeat(object[, times])]

無限に繰り返すイテレータを作成する。

for val in itertools.repeat(1):
    print(val, end=' ')
# 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ...

指定回数繰り返すイテレータを作成する。

for val in itertools.repeat(1, 10):
    print(val, end=' ')
# 1 1 1 1 1 1 1 1 1 1 

累積を計算するイテレータを作成する。

[https://docs.python.jp/3/library/itertools.html#itertools.accumulate:title=itertools.accumulate(iterable[, func])]

累積和を計算するイテレータを作成する。

array = list(range(1, 11))
print(array)  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

accum = list(itertools.accumulate(array))
print(accum)  # [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]

累積積を計算するイテレータを作成する。

array = list(range(1, 11))
print(array)  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

import operator
accum = list(itertools.accumulate(array, operator.mul))
print(accum)  # [1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]

1階の漸化式に基づく数列を計算するイテレータを作成する。

a_{n+1} = 2 a_n + 1 という数列を作成する。
第2引数 func は第1引数に accumulate() で計算しているこれまで計算値、第2引数に入力の配列の今のインデックスの値を受け取る。

array = list(range(1, 11))
print(array)  # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

accum = list(itertools.accumulate(array, lambda total, val: total * 2 + 1))
print(accum)  # [1, 3, 7, 15, 31, 63, 127, 255, 511, 1023]

複数の配列の値を順番に1つずつ取得するイテレータを作成する。

itertools.chain(*iterables)

array1 = ['a', 'b', 'c']
array2 = ['d', 'e', 'f']

result = list(itertools.chain(array1, array2))
print(result)  # ['a', 'b', 'c', 'd', 'e', 'f']

iterable の一覧から値を順番に1つずつ取得するイテレータを作成する。

chain.from_iterable(iterable)

array1 = ['a', 'b', 'c']
array2 = ['d', 'e', 'f']

result = list(itertools.chain.from_iterable([array1, array2]))
print(result)  # ['a', 'b', 'c', 'd', 'e', 'f']

selector の値が True と評価される値だけリストから抽出するイテレータを作成する。

itertools.compress(data, selectors)

array = ['a', 'b', 'c', 'd', 'e', 'f']
selector = [True, False, True, True, False]

result = list(itertools.compress(array, selector))
print(result)  # ['a', 'c', 'd']

predicate が False となる要素だけ返すイテレータを作成する。

itertools.filterfalse(predicate, iterable)

array = list(range(10))

result = list(itertools.filterfalse(lambda x: x % 2 == 0, array))
print(result)  # [1, 3, 5, 7, 9]

predicate が False になるまで値をスキップし、それ以降を1つずつ取得するイテレータを作成する。

itertools.dropwhile(predicate, iterable)

array = list(range(30))

for val in itertools.dropwhile(lambda x: x < 10, array):
    print(val, end=' ')  # 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29

要素が (key, value) で構成されるリストで、同じキーの要素をグルーピングする。

itertools.groupby(iterable, key=None)

from itertools import groupby

array = [("a", 1), ("a", 2), ("b", 5), ("c", 3), ("c", 4)]

for key, group in itertools.groupby(array, lambda x: x[0]):
    print("key: {}, group: {}".format(key, list(group)))
# key: a, group: [('a', 1), ('a', 2)]
# key: b, group: [('b', 5)]
# key: c, group: [('c', 3), ('c', 4)]

iterator に対して、スライスを行うイテレータを作成する。

[https://docs.python.jp/3/library/itertools.html#itertools.islice:title=itertools.islice(iterable, start, stop[, step])]

インデックス指定の方法では、iterator に対してスライス操作は行えないので、islice() を使う。

array = ['a', 'b', 'c', 'd', 'e', 'f']
print(array[1:4:2])  # ['b', 'd']

array = range(10)
print(array[1:4:2])  # range(1, 4, 2)  generator なので、slice はできない。

array = list(itertools.islice(array, 1, 7, 2))
print(array)  # [1, 3, 5]

map() の複数の引数を受け取る関数を使用できるバージョン

itertools.starmap(function, iterable)

array1 = ['a', 'b', 'c']
array2 = ['d', 'e', 'f']

result = list(itertools.starmap(lambda x, y: x + y, zip(array1, array2)))
print(result)  # ['ad', 'be', 'cf']

predicate が真である限り iterable から要素を返すイテレータを作成する。

itertools.takewhile(predicate, iterable)

array = list(range(30))

for val in itertools.takewhile(lambda x: x < 10, array):
    print(val, end=' ')  # 0 1 2 3 4 5 6 7 8 9 

1つの iterator から複数の独立した iterator を作成する。

itertools.tee(iterable, n=2)

array = list(range(18))
print(array)  # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]

ret0, ret1 = itertools.tee(array, 2)
print(list(ret0))
print(list(ret1))

各 iterable の要素をまとめるイテレータを作成する。

itertools.zip_longest(*iterables, fillvalue=None)

array1 = range(10)
array2 = range(5)

# zip() の場合、長さの短い配列が尽きた時点で止まる。
result = list(zip(array1, array2))
print(result)  # [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]

# zip_longest() の場合、長さの短い配列は尽きた以降は fillvalue の値を返すようになる。
result = list(itertools.zip_longest(array1, array2, fillvalue=10))
print(result)  # [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 10), (6, 10), (7, 10), (8, 10), (9, 10)

直積を作成する。

itertools.product(*iterables, repeat=1)

array1 = ['1', '2', '3']
array2 = ['a', 'b', 'c']

product = list(itertools.product(array1, array2))
print(product)
# [('1', 'a'), ('1', 'b'), ('1', 'c'), ('2', 'a'), ('2', 'b'), ('2', 'c'), ('3', 'a'), ('3', 'b'), ('3', 'c')]

順列を作成する。

itertools.permutations(iterable, r=None)

array = ['a', 'b', 'c']
result = list(itertools.permutations(array, 2))

print(result)  # [('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')]

array = ['a', 'b', 'c']
result = list(itertools.permutations(array))

print(result)  # [('a', 'b', 'c'), ('a', 'c', 'b'), ('b', 'a', 'c'), ('b', 'c', 'a'), ('c', 'a', 'b'), ('c', 'b', 'a')]

組み合わせを作成する。

itertools.combinations(iterable, r)

array = ['a', 'b', 'c']
result = list(itertools.combinations(array, 2))

print(result)  # [('a', 'b'), ('a', 'c'), ('b', 'c')]

重複を許す組み合わせを作成する。

itertools.combinations_with_replacement(iterable, r)

array = ['a', 'b', 'c']
result = list(itertools.combinations_with_replacement(array, 2))

print(result)  # [('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), ('c', 'c')]