本記事では、Pythonの標準ライブラリであるitertoolsの使い方を解説します。itertoolsはイテレータを生成するための高速で省メモリなツールを提供します。このライブラリは複雑な繰り返し処理を効率的に実装したい場合に非常に便利です。
itertoolsには以下のような便利な機能があります:
- 組み合わせ系: combinations、permutations、product などで可能な組み合わせを簡単に生成
- 無限イテレータ: count、cycle、repeat で無限シーケンスを省メモリで生成
- イテレータ加工: chain、zip_longest、islice でイテレータを連結、変換
- グループ化: groupby でデータをキーごとにグループ化
- フィルタリング: filterfalse、dropwhile、takewhile で条件に基づくフィルタリング
itertoolsには多くの機能があるため、本記事では利用頻度の高いものに絞って説明します。
import
itertoolsは標準ライブラリであるため、Python環境では以下でimportできます。
import itertools
利用例
組み合わせと順列
組み合わせ(combinations)
要素の組み合わせを生成します。順序は考慮されません。
構文: itertools.combinations(iterable, r)
- iterable: 組み合わせを生成する元となるイテラブル
- r: 各組み合わせの要素数
import itertools
# リストから2要素の組み合わせをすべて生成
result = list(itertools.combinations(['a', 'b', 'c', 'd'], 2))
print(result)
# [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
重複を許す組み合わせ(combinations_with_replacement)
構文: itertools.combinations_with_replacement(iterable, r)
- iterable: 組み合わせを生成する元となるイテラブル
- r: 各組み合わせの要素数
# 重複を許した組み合わせ
result = list(itertools.combinations_with_replacement(['a', 'b', 'c'], 2))
print(result)
# [('a', 'a'), ('a', 'b'), ('a', 'c'), ('b', 'b'), ('b', 'c'), ('c', 'c')]
順列(permutations)
要素の順列を生成します。順序が考慮されます。
構文: itertools.permutations(iterable, r=None)
- iterable: 順列を生成する元となるイテラブル
- r: 各順列の要素数(省略すると全要素を使用)
# 順列(順序あり)
result = list(itertools.permutations(['a', 'b', 'c'], 2))
print(result)
# [('a', 'b'), ('a', 'c'), ('b', 'a'), ('b', 'c'), ('c', 'a'), ('c', 'b')]
無限イテレータ
count
指定した数値から無限にカウントアップするイテレータを生成します。デフォルトでは、開始数値が0から1ずつ増加します。
構文: itertools.count(start=0, step=1)
- start: カウント開始数値
- step: 増加量
# 5から始まる無限カウンタ(最初の5要素だけ表示)
counter = itertools.count(5)
for _ in range(5):
# next(counter) でカウンタの現在の値を取得し、次の値に進める
print(next(counter), end=' ')
# 5 6 7 8 9
cycle
要素を無限に繰り返すイテレータを生成します。
構文: itertools.cycle(iterable)
- iterable: 繰り返す要素を含むイテラブル
# 要素を循環させる
cycle_iter = itertools.cycle(['A', 'B', 'C'])
for _ in range(7):
print(next(cycle_iter), end=' ')
# A B C A B C z
repeat
同じ値を指定回数(または無限に)繰り返すイテレータを生成します。
構文: itertools.repeat(object, times=None)
- object: 繰り返す値
- times: 繰り返す回数(省略すると無限に繰り返す)
# 値を繰り返す(回数制限あり)
repeat_iter = itertools.repeat('X', 5)
print(list(repeat_iter))
# ['X', 'X', 'X', 'X', 'X']
イテレータの加工
chain
複数のイテレータを一つに連結します。
構文: itertools.chain(*iterables)
- iterables: 連結する複数のイテラブル
# 複数のイテレータを連結
result = list(itertools.chain([1, 2], [3, 4], [5, 6]))
print(result)
# [1, 2, 3, 4, 5, 6]
zip_longest
複数のイテラブルを同時に処理し、一番長いイテラブルが終わるまでタプルを作成します。
短いイテラブルの要素が足りなくなった場合、fillvalueで指定した値で埋めます。
構文: itertools.zip_longest(*iterables, fillvalue=None)
- iterables: 処理する複数のイテラブル
- fillvalue: 短いイテラブルを埋めるための値
# 長さの異なるイテレータをzip
result = list(itertools.zip_longest('ABCD', '123', fillvalue='?'))
print(result)
# [('A', '1'), ('B', '2'), ('C', '3'), ('D', '?')]
islice
イテレータをスライスします。
構文: itertools.islice(iterable, start, stop[, step])
- iterable: スライスする元のイテラブル
- start: 開始位置(省略可)
- stop: 終了位置
- step: ステップ幅(省略可)
# イテレータをスライス(開始位置1、終了位置6、ステップ2)
result = list(itertools.islice(range(10), 1, 6, 2))
print(result)
# [1, 3, 5]
グループ化
groupby
連続する同じ値をグループ化し、キーとそのグループのイテレータを返します。
構文: itertools.groupby(iterable, key=None)
- iterable: グループ化する元のイテラブル(通常は同じキーが連続するようにソート済みであること)
- key: グループ化するためのキー関数(省略時は値そのものを使用)
# 値でグループ化
for key, group in itertools.groupby('AAABBBCCDAABBB'):
print(key, ':', list(group))
# A : ['A', 'A', 'A']
# B : ['B', 'B', 'B']
# C : ['C', 'C']
# D : ['D']
# A : ['A', 'A']
# B : ['B', 'B', 'B']
ソート済みデータに対する応用例:
# オブジェクトのプロパティでグループ化
animals = [
{'name': 'dog', 'type': 'mammal'},
{'name': 'cat', 'type': 'mammal'},
{'name': 'snake', 'type': 'reptile'},
{'name': 'frog', 'type': 'amphibian'}
]
# typeでソート
sorted_animals = sorted(animals, key=lambda x: x['type'])
# typeでグループ化
for key, group in itertools.groupby(sorted_animals, key=lambda x: x['type']):
print(key, ':', [animal['name'] for animal in group])
# amphibian : ['frog']
# mammal : ['dog', 'cat']
# reptile : ['snake']
条件フィルタリング
filterfalse
条件を満たさない要素だけを抽出します。
構文: itertools.filterfalse(predicate, iterable)
- predicate: 条件関数
- iterable: フィルタリングする元のイテラブル
# 偶数のみ抽出(奇数をフィルタで除外)
result = list(itertools.filterfalse(lambda x: x % 2, range(10)))
print(result)
# [0, 2, 4, 6, 8]
dropwhile、takewhile
条件を満たす間、要素を除外/取得します。
構文: itertools.dropwhile(predicate, iterable) / itertools.takewhile(predicate, iterable)
- predicate: 条件関数
- iterable: 処理する元のイテラブル
# 5未満の間は除外(5以上から取得開始)
result = list(itertools.dropwhile(lambda x: x < 5, [1, 3, 5, 7, 2, 1]))
print(result)
# [5, 7, 2, 1]
# 5未満の間だけ取得
result = list(itertools.takewhile(lambda x: x < 5, [1, 3, 5, 7, 2, 1]))
print(result)
# [1, 3]
まとめ
itertoolsは効率的なイテレータ処理を行うための強力なツールセットを提供します。特に大量のデータを扱う場合や、組み合わせ、順列などの複雑な処理を簡潔に書きたい場合に非常に役立ちます。メモリ効率が良く、処理速度も速いため、Pythonでの反復処理のパフォーマンスを向上させたい場合には積極的に活用することをお勧めします。
本記事で紹介した例は基本的な使い方の一部に過ぎません。公式ドキュメントを参照することで、より多くの機能を発見することができるでしょう。