概要
itertools
は高速でメモリー効率のよいイテレーターを生成するツールを提供する。
主となる引数にはコレクション(リスト、タプル)を与える。
1 2 3 4 5 6 7 |
from itertools import cycle for n, next in enumerate(cycle(['A', 'B', 'C'])): print(next, end='') if n == 6: break # ABCABCA |
文字列を渡すと文字列中の1文字ずつを要素としたリストと同じ効果。
1 2 3 4 5 |
for n, next in enumerate(cycle("ABC")): print(next, end='') if n == 6: break # ABCABCA |
range()
関数などコレクションを生成する対象も使える。
1 2 3 4 5 |
for n, next in enumerate(cycle(range(3))): print(next, end='') if n == 6: break # 0120120 |
無限イテレーター(infinite iterators)
無限イテレーターは、コレクションの要素を繰り返し取り出し続ける。ループ処理に使う場合、break
文などの終了処理が必要。
count()
itertools.count(start, [step])
- startに与えた数値から初めてstepずつ増加させて取り出す。stepを省略した場合は1ずつ増やす。
1 2 3 4 5 |
for n, digit in enumerate(count(3, 2)): print(digit, end=',') if n==5: break # 3,5,7,9,11,13, |
cycle()
itertools.cycle(p)
- コレクションpを与えて、その要素p0, p1, …, plastを取り出し、その後p0へ戻って繰り返す。
1 2 3 4 5 6 7 |
from itertools import cycle for n, digit in enumerate(cycle(range(4))): print(digit, end=',') if n==10: break # 0,1,2,3,0,1,2,3,0,1,2, |
repeat()
itertools.repeat(elem [, n])
- elemで与えた要素を第2引数で与えた数値の回数分繰り返す。第2引数を省略すると無限回繰り返す。
1 2 3 4 |
for ch in repeat('Ha', 8): print(ch, end='') # HaHaHaHaHaHaHaHa |
組み合わせイテレーター(combinatoric iterator)
組み合わせイテレーターは、コレクションの要素から指定した数を取り出し、それらの直積、順列、組み合わせを結果とする。
product()
itertools.product(p [, repeat=n])
- コレクション
p
の要素について、repeat
で指定した数の直積の結果をタプルで返す。同一の要素、順番の異なる同じ組み合わせの要素を持つ結果を許す。 - 第2引数
repeat
を省略すると要素数1のタプルを返す。
1 2 3 4 5 6 7 8 9 10 11 12 |
from itertools import product for str in product(['A', 'B', 'C'], repeat=2): print(str, end='') print() for str in product(['A', 'B', 'C']): print(str, end='') # ('A', 'A')('A', 'B')('A', 'C')('B', 'A')('B', 'B')('B', 'C')('C', 'A')('C', 'B')('C', 'C') # ('A',)('B',)('C',) |
permutations
itertools.permutations(p [, r=n])
- コレクション
p
の要素について、r
で指定した数の順列の結果をタプルで返す。統一要素の組はなく、同じ組み合わせの要素の順番が異なる結果は許す。 - 第2引数は
repeat
ではなくr
である点に注意。r
を省略すると、全ての要素に対する組み合わせを返す。
1 2 3 4 5 6 7 8 9 10 11 12 |
from itertools import permutations for str in permutations("ABC", r=2): print(str, end='') print() for str in permutations("ABC"): print(str, end='') # ('A', 'B')('A', 'C')('B', 'A')('B', 'C')('C', 'A')('C', 'B') # ('A', 'B', 'C')('A', 'C', 'B')('B', 'A', 'C')('B', 'C', 'A')('C', 'A', 'B')('C', 'B', 'A') |
combinations
itertools.combinations(p, repeat=n)
- コレクション
p
の要素について、repeat
で指定した数の組み合わせの結果をタプルで返す。同一要素の組はなく、同じ組み合わせで順番が異なるものは同じ結果となる。 - 第2引数
r
は省略できない。省略するとそれ以降の実行がされないなど動作が不定になる。
1 2 3 4 5 6 |
from itertools import combinations for str in combinations("ABC", r=2): print(str, end='') # ('A', 'B')('A', 'C')('B', 'C'), |
combinations_with_replacement
itertools.combinations_with_replacement(iterable, r)
- 組み合わせに、同一要素の重複を許す。
-
- 第2引数
r
は省略できない。省略するとそれ以降の実行がされないなど動作が不定になる。
- 第2引数
1 2 3 4 5 6 |
from itertools import combinations for str in combinations("ABC", r=2): print(str, end='') # ('A', 'A')('A', 'B')('A', 'C')('B', 'B')('B', 'C')('C', 'C') |
特に役立ちそうなもの
chain~リストの結合に使える
itertools.chain(*iterables)
- 複数のiterableを与え、それらの内容を並べた1つのイテレーターを返す。引数の先頭の
'*'
は複数のiterablesを展開したものであることを表す。
戻り値はイテレーターオブジェクト。
1 2 3 4 5 |
from itertools import chain print(chain([0, 1, 2, 3], [4, 5])) # <itertools.chain object at 0x028081B0> |
list()
関数でリスト化すると、展開されたリストが得られる。
1 2 3 |
print(list(chain([0, 1, 2, 3], [4, 5]))) # [0, 1, 2, 3, 4, 5] |
引数にはRange
のようなイテレーターも混在可能。
1 2 3 |
print(list(chain(range(3), [3, 4, 5]))) # [0, 1, 2, 3, 4, 5] |
蛇足だが単一のiteratableはそのまま返されるだけ。
1 2 3 |
print(list(chain([0, 1, 2, 3, 4, 5]))) # [0, 1, 2, 3, 4, 5] |
chain.from_iterabble~2次元リストの展開に
itertools.chain.from_iterable(iterables)
- 複数のiterableを与え、それらの内容を並べた1つのイテレーターを返す。引数の先頭に’*’がないのは、引数がiterableを要素に持つiterableであることを表す。
たとえば複数のリストを含む2次元リストの全要素を1次元に展開可能。from_iterable()
はchain
のコンストラクターの一つであり、モジュールのインポート方法とコンストラクターの呼び方に注意。
1 2 3 4 5 |
from itertools import chain print(list(chain.from_iterable([[0], [1, 2], [3, 4, 5]]))) # [0, 1, 2, 3, 4, 5] |
1次元リストは要素がiterableでないのでエラー。
1 2 3 |
print(list(chain.from_iterable([0, 1, 2]))) # TypeError: 'int' object is not iterable |
ndarrayを要素とするリストは、要素の配列が展開されて1次元リストに。
1 2 3 |
print(list(chain.from_iterable([np.array([1]), np.array([2, 3])]))) # [1, 2, 3] |
ndarrayの2次元配列も展開可能。結果をリストでほしいときはlist()
関数、配列でほしいときは一旦list()
関数でリスト化してからnumpy.array()
で配列化。
1 2 3 4 5 6 7 8 9 10 |
ary = np.array([[1, 2], [3, 4]]) print(ary) # [[1 2] # [3 4]] print(list(chain.from_iterable(ary))) # [1, 2, 3, 4] print(np.array(list(chain.from_iterable(ary)))) # [1 2 3 4] |
zip_longest~最長の引数に合わせるzip
itertools.zip_longest(*iterables, fillvalue=None)
- 複数のiterableを与え、それらを先頭から順にまとめたイテレーターを返す。結果は最も長いiterableに合わせられ、足りない値は
fillvalue
で埋められる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
from itertools import zip_longest iterable1 = "ABCDE" iterable2 = [1, 2, 3] for item1, item2 in zip_longest(iterable1, iterable2): print(item1, item2) # A 1 # B 2 # C 3 # D None # E None for item1, item2 in zip_longest(iterable1, iterable2, fillvalue=0): print(item1, item2) # A 1 # B 2 # C 3 # D 0 # E 0 |