itertools.chain() / itertools.islice() / itertools.count()
| 対応: | Python 2(2000) |
|---|
直積とは、2つのグループから1つずつ選ぶ全ての組み合わせのことです。例えば色3種×サイズ3種なら9通りになります。直積を生成するには『itertools.product()』を参照してください。
『itertools』モジュールはイテレータを操作するためのツールを提供します。『itertools.chain()』は複数のイテラブルを連結して1つのイテレータとして扱えます。『itertools.islice()』はイテレータをスライスし、『itertools.count()』は無限に数値を生成します。これらは遅延評価(lazy evaluation)で動作するため、大量のデータも省メモリで処理できます。
構文
import itertools # 複数のイテラブルを連結 itertools.chain(iterable1, iterable2, ...) # イテレータをスライス itertools.islice(iterable, stop) itertools.islice(iterable, start, stop, step) # 無限カウンタ itertools.count(start=0, step=1) # 無限サイクル itertools.cycle(iterable) # 要素の繰り返し itertools.repeat(object, times=None)
関数一覧
| 関数 | 概要 |
|---|---|
| chain(*iterables) | 複数のイテラブルを連結して1つのイテレータにする。 |
| chain.from_iterable(iterable) | ネストされたイテラブルを1段階フラットにする。 |
| islice(iterable, stop) | イテレータをスライスして指定範囲の要素を返す。 |
| count(start, step) | startから始まりstepずつ増加する無限の数列を生成する。 |
| cycle(iterable) | イテラブルの要素を無限に繰り返す。 |
| repeat(obj, times) | objをtimes回(省略で無限回)繰り返すイテレータを返す。 |
サンプルコード
itertools_chain.py
import itertools # chain: 複数リストを連結 a = [1, 2, 3] b = [4, 5, 6] c = ['x', 'y'] result = list(itertools.chain(a, b, c)) print(result) # chain.from_iterable: ネストされたリストをフラット化 nested = [[1, 2], [3, 4], [5, 6]] flat = list(itertools.chain.from_iterable(nested)) print(flat)
python3 itertools_chain.py [1, 2, 3, 4, 5, 6, 'x', 'y'] [1, 2, 3, 4, 5, 6]
itertools_islice.py
import itertools # islice: 無限イテレータを安全に扱う counter = itertools.count(10, 2) sliced = list(itertools.islice(counter, 5)) print(sliced) # islice: start, stop, step を指定 data = range(100) result = list(itertools.islice(data, 0, 20, 3)) print(result)
python3 itertools_islice.py [10, 12, 14, 16, 18] [0, 3, 6, 9, 12, 15, 18]
itertools_cycle_repeat.py
import itertools
# cycle: 繰り返しパターンの生成
fighters = ['孫悟空', 'ベジータ', 'クリリン']
cycled = list(itertools.islice(itertools.cycle(fighters), 7))
print(cycled)
# repeat: 同じ値をn回繰り返す
repeated = list(itertools.repeat('hello', 3))
print(repeated)
# map と組み合わせてn乗のリストを生成
squares = list(map(pow, range(5), itertools.repeat(2)))
print(squares)
python3 itertools_cycle_repeat.py ['孫悟空', 'ベジータ', 'クリリン', '孫悟空', 'ベジータ', 'クリリン', '孫悟空'] ['hello', 'hello', 'hello'] [0, 1, 4, 9, 16]
よくあるミス
よくあるミス1: chain() の引数に要素を直接渡してしまう
リストをそのまま渡さずに、展開した要素を渡してしまうミスです。chain() はイテラブルを引数に受け取ります。
mistake1_ng.py
import itertools
warriors = ['孫悟空', 'ベジータ', 'クリリン']
allies = ['ピッコロ', '悟飯']
# NG: リストをイテラブルとして渡さず、要素を直接渡している
result = list(itertools.chain('孫悟空', 'ベジータ'))
print(result)
python3 mistake1_ng.py ['孫', '悟', '空', 'ベ', 'ジ', 'ー', 'タ']
文字列を直接渡すと、文字列自体がイテラブルとして扱われ、1文字ずつに分解されます。リスト変数をそのまま渡すのが正しい使い方です。
mistake1_ok.py
import itertools warriors = ['孫悟空', 'ベジータ', 'クリリン'] allies = ['ピッコロ', '悟飯'] # OK: リスト変数を渡す result = list(itertools.chain(warriors, allies)) print(result)
python3 mistake1_ok.py ['孫悟空', 'ベジータ', 'クリリン', 'ピッコロ', '悟飯']
よくあるミス2: 無限イテレータを islice なしで list() に渡す
count() や cycle() はイテレータを無限に生成します。islice() で個数を制限せずに list() に渡すと、メモリを使い切りプログラムがフリーズします。
mistake2_ng.py
import itertools # NG: 無限イテレータをそのまま list() に渡す(フリーズする) # result = list(itertools.count(1)) # result = list(itertools.cycle(['孫悟空', 'ベジータ']))
mistake2_ok.py
import itertools # OK: islice() で取り出す個数を制限する result = list(itertools.islice(itertools.count(1), 5)) print(result) cycled = list(itertools.islice(itertools.cycle(['孫悟空', 'ベジータ']), 5)) print(cycled)
python3 mistake2_ok.py [1, 2, 3, 4, 5] ['孫悟空', 'ベジータ', '孫悟空', 'ベジータ', '孫悟空']
概要
『chain()』はリストの結合に『+』演算子を使うよりも効率的で、実際には要素をコピーせずイテレータを繋いで返します。大量のリストを結合する場合に特に効果的です。
『islice()』は無限イテレータと組み合わせて使うことが多く、通常のスライス構文([start:stop])はイテレータには使えないため、isliceが代替手段となります。
『count()』・『cycle()』・『repeat()』は無限に要素を生成するため、必ずisliceや条件付きのbreakと組み合わせて使います。これらはzip()と組み合わせることで、連番付きや繰り返しパターンのデータ生成にも活用できます。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。