pythonでのネストされたループを減らすためのよく知られた方法を考察。
2重のネストループ程度であればありがちな例でも問題ないが、3重、4重となってくるとitertoolsのありがたみがわかる。
10×10の座標を全走査するときなど
//ありがちなネストループの例
for x in range(10):
for y in range(10):
print("%d, %d" % (x,y))
itertools.productを使って全通りの組み合わせを出す。
import itertools
for x, y in itertools.product(range(10), range(10)): #Xの10通り、Yの10通りの全組み合わせ
print("%d,%d" % (x,y))
※itertoolsはイテレータを生成しているので、全通りの操作をするために膨大な件数の組み合わせを作ったとしてもメモリを大量に消費することはない。
x,y,zの3つのネストでも同じようにネストせずに記述できる。
import itertools
for x, y,z in itertools.product(range(10), range(10), range(10)):
print("%d,%d,%d" % (x,y,z))
配列、文字列の部分列を全通り取得したい場合
例えば、文字列”ABCDE”の部分文字列を、"A", "AB", "ABC", "ABCD", "ABCDE", "B", "BC"...
のように取得したい場合。
//ありがちなネストループの例
text = "ABCDE"
l = len(text)
for s in range(l+1): #開始インデックスを外側のループに
for e in range(s+1, l+1): #終了インデックスを開始インデックスから始めて末端まで
print(text[s:e]) #部分文字列取得
itertools.combinationsを使って、開始、終了インデックスの決定のパターンを取得する例。
// itertools.combinationsをつかったインデックスの組み合わせ取得
text = "ABCDE"
l = len(text)
for s, e in itertools.combinations(range(l+1), 2):
print(text[s:e])
参考:組み合わせや順列の列挙に便利なitertoolsの機能
10.1. itertools — 効率的なループ実行のためのイテレータ生成関数 — Python 3.5.1 ドキュメント