itertools —効率的なループのためのイテレータを作成する関数—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.8/library/itertools
移動先:案内検索

itertools —効率的なループのためのイテレータを作成する関数


このモジュールは、APL、Haskell、およびSMLの構成に触発された多数の iterator ビルディングブロックを実装します。 それぞれがPythonに適した形式に再キャストされています。

このモジュールは、単独で、または組み合わせて使用できる、高速でメモリ効率の高いツールのコアセットを標準化します。 これらが一緒になって「イテレータ代数」を形成し、純粋なPythonで特殊なツールを簡潔かつ効率的に構築できるようにします。

たとえば、SMLは、シーケンスf(0), f(1), ...を生成する集計ツールtabulate(f)を提供します。 map()count()を組み合わせてmap(f, count())を形成することにより、Pythonでも同じ効果を得ることができます。

これらのツールとそれに組み込まれているツールは、 operator モジュールの高速機能でもうまく機能します。 たとえば、乗算演算子を2つのベクトルにマッピングして、効率的な内積sum(map(operator.mul, vector1, vector2))を形成できます。

無限イテレータ:

イテレータ 引数 結果
count() スタート、[ステップ] start、start + step、start + 2 * step、… count(10) --> 10 11 12 13 14 ...
cycle() p p0、p1、…プラスト、p0、p1、… cycle('ABCD') --> A B C D A B C D ...
repeat() elem [、n] elem、elem、elem、…無限にまたは最大n回 repeat(10, 3) --> 10 10 10

最短の入力シーケンスで終了するイテレータ:

イテレータ 引数 結果
accumulate() p [、func] p0、p0 + p1、p0 + p1 + p2、… accumulate([1,2,3,4,5]) --> 1 3 6 10 15
chain() p、q、… p0、p1、…プラスト、q0、q1、… chain('ABC', 'DEF') --> A B C D E F
chain.from_iterable() 反復可能 p0、p1、…プラスト、q0、q1、… chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
compress() データ、セレクター (s [0]の場合はd [0])、(s [1]の場合はd [1])、… compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
dropwhile() pred、seq seq [n]、seq [n + 1]、predが失敗したときに開始 dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
filterfalse() pred、seq pred(elem)がfalseであるseqの要素 filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8
groupby() iterable [、key] key(v)の値でグループ化されたサブイテレータ
islice() seq、[start、] stop [、step] seq [start:stop:step]の要素 islice('ABCDEFG', 2, None) --> C D E F G
starmap() func、seq func(* seq [0])、func(* seq [1])、… starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000
takewhile() pred、seq seq [0]、seq [1]、predが失敗するまで takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
tee() それ、n it1、it2、…itnは1つのイテレータをnに分割します
zip_longest() p、q、… (p [0]、q [0])、(p [1]、q [1])、… zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-

組み合わせイテレータ:

イテレータ 引数 結果
product() p、q、…[繰り返し= 1] ネストされたforループに相当するデカルト積
permutations() p [、r] r-長さのタプル、すべての可能な順序、繰り返される要素なし
combinations() p、r r-長さのタプル、ソートされた順序で、繰り返される要素なし
combinations_with_replacement() p、r rの長さのタプル、ソートされた順序で、要素が繰り返されている
結果
product('ABCD', repeat=2) AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
permutations('ABCD', 2) AB AC AD BA BC BD CA CB CD DA DB DC
combinations('ABCD', 2) AB AC AD BC BD CD
combinations_with_replacement('ABCD', 2) AA AB AC AD BB BC BD CC CD DD

Itertool関数

次のモジュール関数は、すべてのイテレータを作成して返します。 無限の長さのストリームを提供するものもあるため、ストリームを切り捨てる関数またはループからのみアクセスする必要があります。

itertools.accumulate(iterable[, func, *, initial=None])

累積合計、または他のバイナリ関数の累積結果(オプションの func 引数で指定)を返すイテレーターを作成します。

func が指定されている場合、それは2つの引数の関数である必要があります。 入力 iterable の要素は、 func への引数として受け入れることができる任意のタイプにすることができます。 (たとえば、デフォルトの加算演算では、要素は Decimal または Fraction を含む任意の加算可能なタイプにすることができます。)

通常、出力される要素の数は、反復可能な入力と一致します。 ただし、キーワード引数 initial が指定されている場合、累積は initial 値で始まり、出力には入力反復可能要素より1つ多い要素が含まれます。

ほぼ同等:

def accumulate(iterable, func=operator.add, *, initial=None):
    'Return running totals'
    # accumulate([1,2,3,4,5]) --> 1 3 6 10 15
    # accumulate([1,2,3,4,5], initial=100) --> 100 101 103 106 110 115
    # accumulate([1,2,3,4,5], operator.mul) --> 1 2 6 24 120
    it = iter(iterable)
    total = initial
    if initial is None:
        try:
            total = next(it)
        except StopIteration:
            return
    yield total
    for element in it:
        total = func(total, element)
        yield total

func 引数にはいくつかの用途があります。 実行中の最小値の場合は min()、実行中の最大値の場合は max()、実行中の製品の場合は operator.mul()に設定できます。 償却表は、利息を累積して支払いを適用することで作成できます。 一次漸化式は、反復可能で初期値を指定し、 func 引数の累積合計のみを使用することでモデル化できます。

>>> data = [3, 4, 6, 2, 1, 9, 0, 7, 5, 8]
>>> list(accumulate(data, operator.mul))     # running product
[3, 12, 72, 144, 144, 1296, 0, 0, 0, 0]
>>> list(accumulate(data, max))              # running maximum
[3, 4, 6, 6, 6, 9, 9, 9, 9, 9]

# Amortize a 5% loan of 1000 with 4 annual payments of 90
>>> cashflows = [1000, -90, -90, -90, -90]
>>> list(accumulate(cashflows, lambda bal, pmt: bal*1.05 + pmt))
[1000, 960.0, 918.0, 873.9000000000001, 827.5950000000001]

# Chaotic recurrence relation https://en.wikipedia.org/wiki/Logistic_map
>>> logistic_map = lambda x, _:  r * x * (1 - x)
>>> r = 3.8
>>> x0 = 0.4
>>> inputs = repeat(x0, 36)     # only the initial value is used
>>> [format(x, '.2f') for x in accumulate(inputs, logistic_map)]
['0.40', '0.91', '0.30', '0.81', '0.60', '0.92', '0.29', '0.79', '0.63',
 '0.88', '0.39', '0.90', '0.33', '0.84', '0.52', '0.95', '0.18', '0.57',
 '0.93', '0.25', '0.71', '0.79', '0.63', '0.88', '0.39', '0.91', '0.32',
 '0.83', '0.54', '0.95', '0.20', '0.60', '0.91', '0.30', '0.80', '0.60']

最終的な累積値のみを返す同様の関数については、 functools.reduce()を参照してください。

バージョン3.2の新機能。

バージョン3.3で変更:オプションの func パラメーターが追加されました。

バージョン3.8で変更:オプションの initial パラメーターを追加しました。

itertools.chain(*iterables)

最初のイテレータから要素がなくなるまで要素を返し、次にすべてのイテレータがなくなるまで次のイテレータに進むイテレータを作成します。 連続するシーケンスを単一のシーケンスとして扱うために使用されます。 ほぼ同等:

def chain(*iterables):
    # chain('ABC', 'DEF') --> A B C D E F
    for it in iterables:
        for element in it:
            yield element
classmethod chain.from_iterable(iterable)

chain()の代替コンストラクター。 遅延評価される単一の反復可能な引数から連鎖入力を取得します。 ほぼ同等:

def from_iterable(iterables):
    # chain.from_iterable(['ABC', 'DEF']) --> A B C D E F
    for it in iterables:
        for element in it:
            yield element
itertools.combinations(iterable, r)

入力 iterable から要素の r 長さのサブシーケンスを返します。

組み合わせタプルは、入力 iterable の順序に従って辞書式順序で発行されます。 したがって、入力 iterable がソートされている場合、組み合わせタプルはソートされた順序で生成されます。

要素は、値ではなく、位置に基づいて一意として扱われます。 したがって、入力要素が一意である場合、各組み合わせに繰り返し値はありません。

ほぼ同等:

def combinations(iterable, r):
    # combinations('ABCD', 2) --> AB AC AD BC BD CD
    # combinations(range(4), 3) --> 012 013 023 123
    pool = tuple(iterable)
    n = len(pool)
    if r > n:
        return
    indices = list(range(r))
    yield tuple(pool[i] for i in indices)
    while True:
        for i in reversed(range(r)):
            if indices[i] != i + n - r:
                break
        else:
            return
        indices[i] += 1
        for j in range(i+1, r):
            indices[j] = indices[j-1] + 1
        yield tuple(pool[i] for i in indices)

combinations()のコードは、要素が並べ替えられていないエントリをフィルタリングした後、 permutations()のサブシーケンスとして表すこともできます(入力プール内の位置に従って) :

def combinations(iterable, r):
    pool = tuple(iterable)
    n = len(pool)
    for indices in permutations(range(n), r):
        if sorted(indices) == list(indices):
            yield tuple(pool[i] for i in indices)

返されるアイテムの数は、0 <= r <= nの場合はn! / r! / (n-r)!r > nの場合はゼロです。

itertools.combinations_with_replacement(iterable, r)

入力 iterable から要素の r 長さのサブシーケンスを返し、個々の要素を複数回繰り返すことができます。

組み合わせタプルは、入力 iterable の順序に従って辞書式順序で発行されます。 したがって、入力 iterable がソートされている場合、組み合わせタプルはソートされた順序で生成されます。

要素は、値ではなく、位置に基づいて一意として扱われます。 したがって、入力要素が一意である場合、生成される組み合わせも一意になります。

ほぼ同等:

def combinations_with_replacement(iterable, r):
    # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC
    pool = tuple(iterable)
    n = len(pool)
    if not n and r:
        return
    indices = [0] * r
    yield tuple(pool[i] for i in indices)
    while True:
        for i in reversed(range(r)):
            if indices[i] != n - 1:
                break
        else:
            return
        indices[i:] = [indices[i] + 1] * (r - i)
        yield tuple(pool[i] for i in indices)

combinations_with_replacement()のコードは、要素が並べ替えられた順序ではないエントリをフィルタリングした後、 product()のサブシーケンスとして表すこともできます(入力プール内の位置に従って) :

def combinations_with_replacement(iterable, r):
    pool = tuple(iterable)
    n = len(pool)
    for indices in product(range(n), repeat=r):
        if sorted(indices) == list(indices):
            yield tuple(pool[i] for i in indices)

n > 0の場合、返されるアイテムの数は(n+r-1)! / r! / (n-1)!です。

バージョン3.1の新機能。

itertools.compress(data, selectors)

データの要素をフィルタリングして、セレクターTrueと評価される対応する要素を持つ要素のみを返すイテレーターを作成します。 データまたはセレクターイテラブルのいずれかが使い果たされると停止します。 ほぼ同等:

def compress(data, selectors):
    # compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F
    return (d for d, s in zip(data, selectors) if s)

バージョン3.1の新機能。

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

数値 start で始まる等間隔の値を返すイテレーターを作成します。 多くの場合、 map()の引数として使用され、連続するデータポイントを生成します。 また、 zip()とともに使用して、シーケンス番号を追加します。 ほぼ同等:

def count(start=0, step=1):
    # count(10) --> 10 11 12 13 14 ...
    # count(2.5, 0.5) -> 2.5 3.0 3.5 ...
    n = start
    while True:
        yield n
        n += step

浮動小数点数でカウントする場合、(start + step * i for i in count())のような乗法コードに置き換えることで、より高い精度が得られる場合があります。

バージョン3.1で変更: step 引数を追加し、非整数引数を許可しました。

itertools.cycle(iterable)

イテレータから要素を返し、それぞれのコピーを保存するイテレータを作成します。 iterableが使い果たされたら、保存されたコピーから要素を返します。 無期限に繰り返します。 ほぼ同等:

def cycle(iterable):
    # cycle('ABCD') --> A B C D A B C D A B C D ...
    saved = []
    for element in iterable:
        yield element
        saved.append(element)
    while saved:
        for element in saved:
              yield element

ツールキットのこのメンバーは、(反復可能オブジェクトの長さに応じて)かなりの補助記憶装置を必要とする場合があることに注意してください。

itertools.dropwhile(predicate, iterable)

述語が真である限り、イテレータから要素を削除するイテレータを作成します。 その後、すべての要素を返します。 イテレータは、述語が最初にfalseになるまで any 出力を生成しないため、起動時間が長くなる可能性があることに注意してください。 ほぼ同等:

def dropwhile(predicate, iterable):
    # dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1
    iterable = iter(iterable)
    for x in iterable:
        if not predicate(x):
            yield x
            break
    for x in iterable:
        yield x
itertools.filterfalse(predicate, iterable)

述語がFalseである要素のみを返す、反復可能から要素をフィルター処理するイテレーターを作成します。 述語Noneの場合、falseの項目を返します。 ほぼ同等:

def filterfalse(predicate, iterable):
    # filterfalse(lambda x: x%2, range(10)) --> 0 2 4 6 8
    if predicate is None:
        predicate = bool
    for x in iterable:
        if not predicate(x):
            yield x
itertools.groupby(iterable, key=None)

iterable から連続するキーとグループを返すイテレーターを作成します。 key は、各要素のキー値を計算する関数です。 指定されていない場合、またはNoneの場合、 key はデフォルトで恒等関数になり、要素を変更せずに返します。 一般に、イテラブルは同じキー関数ですでにソートされている必要があります。

groupby()の操作は、Unixのuniqフィルターに似ています。 キー関数の値が変更されるたびに、ブレークまたは新しいグループが生成されます(そのため、通常、同じキー関数を使用してデータを並べ替える必要があります)。 この動作は、入力順序に関係なく共通の要素を集約するSQLのGROUPBYとは異なります。

返されるグループ自体は、基になるイテレータを groupby()と共有するイテレータです。 ソースが共有されているため、 groupby()オブジェクトを進めると、前のグループは表示されなくなります。 したがって、そのデータが後で必要になった場合は、リストとして保存する必要があります。

groups = []
uniquekeys = []
data = sorted(data, key=keyfunc)
for k, g in groupby(data, keyfunc):
    groups.append(list(g))      # Store group iterator as a list
    uniquekeys.append(k)

groupby()は、おおよそ次のものと同等です。

class groupby:
    # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
    # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
    def __init__(self, iterable, key=None):
        if key is None:
            key = lambda x: x
        self.keyfunc = key
        self.it = iter(iterable)
        self.tgtkey = self.currkey = self.currvalue = object()
    def __iter__(self):
        return self
    def __next__(self):
        self.id = object()
        while self.currkey == self.tgtkey:
            self.currvalue = next(self.it)    # Exit on StopIteration
            self.currkey = self.keyfunc(self.currvalue)
        self.tgtkey = self.currkey
        return (self.currkey, self._grouper(self.tgtkey, self.id))
    def _grouper(self, tgtkey, id):
        while self.id is id and self.currkey == tgtkey:
            yield self.currvalue
            try:
                self.currvalue = next(self.it)
            except StopIteration:
                return
            self.currkey = self.keyfunc(self.currvalue)
itertools.islice(iterable, stop)
itertools.islice(iterable, start, stop[, step])

イテレータから選択した要素を返すイテレータを作成します。 start がゼロ以外の場合、iterableの要素はstartに到達するまでスキップされます。 その後、 step が1より高く設定されてアイテムがスキップされない限り、要素は連続して返されます。 stopNoneの場合、イテレータが使い果たされるまで反復が続行されます。 それ以外の場合は、指定された位置で停止します。 通常のスライスとは異なり、 islice()は、 startstop 、または step の負の値をサポートしていません。 内部構造がフラット化されているデータから関連フィールドを抽出するために使用できます(たとえば、複数行のレポートでは、3行ごとに名前フィールドがリストされる場合があります)。 ほぼ同等:

def islice(iterable, *args):
    # islice('ABCDEFG', 2) --> A B
    # islice('ABCDEFG', 2, 4) --> C D
    # islice('ABCDEFG', 2, None) --> C D E F G
    # islice('ABCDEFG', 0, None, 2) --> A C E G
    s = slice(*args)
    start, stop, step = s.start or 0, s.stop or sys.maxsize, s.step or 1
    it = iter(range(start, stop, step))
    try:
        nexti = next(it)
    except StopIteration:
        # Consume *iterable* up to the *start* position.
        for i, element in zip(range(start), iterable):
            pass
        return
    try:
        for i, element in enumerate(iterable):
            if i == nexti:
                yield element
                nexti = next(it)
    except StopIteration:
        # Consume to *stop*.
        for i, element in zip(range(i + 1, stop), iterable):
            pass

startNoneの場合、反復はゼロから始まります。 stepNoneの場合、ステップはデフォルトで1になります。

itertools.permutations(iterable, r=None)

iterable 内の要素の連続する r 長さの順列を返します。

r が指定されていないか、Noneの場合、 r はデフォルトで iterable の長さになり、可能なすべてのフルレングスの順列が生成されます。 。

順列タプルは、入力 iterable の順序に従って辞書式順序で発行されます。 したがって、入力 iterable がソートされている場合、組み合わせタプルはソートされた順序で生成されます。

要素は、値ではなく、位置に基づいて一意として扱われます。 したがって、入力要素が一意である場合、各順列に繰り返し値はありません。

ほぼ同等:

def permutations(iterable, r=None):
    # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
    # permutations(range(3)) --> 012 021 102 120 201 210
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    if r > n:
        return
    indices = list(range(n))
    cycles = list(range(n, n-r, -1))
    yield tuple(pool[i] for i in indices[:r])
    while n:
        for i in reversed(range(r)):
            cycles[i] -= 1
            if cycles[i] == 0:
                indices[i:] = indices[i+1:] + indices[i:i+1]
                cycles[i] = n - i
            else:
                j = cycles[i]
                indices[i], indices[-j] = indices[-j], indices[i]
                yield tuple(pool[i] for i in indices[:r])
                break
        else:
            return

順列()のコードは、 product()のサブシーケンスとして表現することもでき、繰り返し要素を持つエントリ(入力プールの同じ位置からのエントリ)を除外するようにフィルタリングされます。

def permutations(iterable, r=None):
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    for indices in product(range(n), repeat=r):
        if len(set(indices)) == r:
            yield tuple(pool[i] for i in indices)

返されるアイテムの数は、0 <= r <= nの場合はn! / (n-r)!r > nの場合はゼロです。

itertools.product(*iterables, repeat=1)

入力反復可能のデカルト積。

ジェネレータ式のネストされたforループとほぼ同等です。 たとえば、product(A, B)((x,y) for x in A for y in B)と同じ値を返します。

ネストされたループは走行距離計のように循環し、右端の要素が反復ごとに進みます。 このパターンは辞書式順序を作成するため、入力の反復可能オブジェクトがソートされている場合、製品タプルはソートされた順序で発行されます。

iterableとそれ自体の積を計算するには、オプションの repeat キーワード引数を使用して繰り返し回数を指定します。 たとえば、product(A, repeat=4)product(A, A, A, A)と同じ意味です。

この関数は、実際の実装がメモリに中間結果を構築しないことを除いて、次のコードとほぼ同等です。

def product(*args, repeat=1):
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
    pools = [tuple(pool) for pool in args] * repeat
    result = [[../]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)
itertools.repeat(object[, times])

オブジェクトを何度も返すイテレータを作成します。 times 引数が指定されていない限り、無期限に実行されます。 呼び出された関数への不変パラメーターの map()への引数として使用されます。 zip()とともに使用して、タプルレコードの不変部分を作成します。

ほぼ同等:

def repeat(object, times=None):
    # repeat(10, 3) --> 10 10 10
    if times is None:
        while True:
            yield object
    else:
        for i in range(times):
            yield object

repeat の一般的な使用法は、定数値のストリームを map または zip に提供することです。

>>> list(map(pow, range(10), repeat(2)))
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
itertools.starmap(function, iterable)

iterableから取得した引数を使用して関数を計算するイテレータを作成します。 map()の代わりに、引数パラメーターが単一の反復可能オブジェクトからのタプルに既にグループ化されている場合に使用されます(データは「事前に圧縮」されています)。 map()starmap()の違いは、function(a,b)function(*c)の違いと同じです。 ほぼ同等:

def starmap(function, iterable):
    # starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000
    for args in iterable:
        yield function(*args)
itertools.takewhile(predicate, iterable)

述語が真である限り、イテレータから要素を返すイテレータを作成します。 ほぼ同等:

def takewhile(predicate, iterable):
    # takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
    for x in iterable:
        if predicate(x):
            yield x
        else:
            break
itertools.tee(iterable, n=2)

単一のイテレータから n の独立したイテレータを返します。

次のPythonコードは、 tee の機能を説明するのに役立ちます(ただし、実際の実装はより複雑で、基になる FIFO キューを1つだけ使用します)。

ほぼ同等:

def tee(iterable, n=2):
    it = iter(iterable)
    deques = [collections.deque() for i in range(n)]
    def gen(mydeque):
        while True:
            if not mydeque:             # when the local deque is empty
                try:
                    newval = next(it)   # fetch a new value and
                except StopIteration:
                    return
                for d in deques:        # load it to all the deques
                    d.append(newval)
            yield mydeque.popleft()
    return tuple(gen(d) for d in deques)

tee()が分割されたら、元の iterable を他の場所で使用しないでください。 そうしないと、 iterable は、ティーオブジェクトに通知されずに進む可能性があります。

teeイテレータはスレッドセーフではありません。 元の iterable がスレッドセーフであっても、同じ tee()呼び出しによって返されるイテレータを同時に使用すると、 RuntimeError が発生する場合があります。

このitertoolは、(保存する必要のある一時データの量に応じて)かなりの補助記憶装置を必要とする場合があります。 一般に、あるイテレータが別のイテレータが開始する前にほとんどまたはすべてのデータを使用する場合は、 tee()の代わりに list()を使用する方が高速です。

itertools.zip_longest(*iterables, fillvalue=None)

各イテレータから要素を集約するイテレータを作成します。 イテラブルの長さが不均一な場合、欠落している値は fillvalue で埋められます。 反復は、最長の反復がなくなるまで続きます。 ほぼ同等:

def zip_longest(*args, fillvalue=None):
    # zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
    iterators = [iter(it) for it in args]
    num_active = len(iterators)
    if not num_active:
        return
    while True:
        values = []
        for i, it in enumerate(iterators):
            try:
                value = next(it)
            except StopIteration:
                num_active -= 1
                if not num_active:
                    return
                iterators[i] = repeat(fillvalue)
                value = fillvalue
            values.append(value)
        yield tuple(values)

反復可能オブジェクトの1つが潜在的に無限である場合、 zip_longest()関数は、呼び出しの数を制限するものでラップする必要があります(たとえば、 islice()または takewhile( ))。 指定しない場合、 fillvalue のデフォルトはNoneです。


Itertoolsレシピ

このセクションでは、既存のitertoolsをビルディングブロックとして使用して拡張ツールセットを作成するためのレシピを示します。

実質的にすべてのこれらのレシピと他の多くのレシピは、Python PackageIndexにある more-itertoolsプロジェクトからインストールできます。

pip install more-itertools

拡張ツールは、基盤となるツールセットと同じ高性能を提供します。 反復可能オブジェクト全体を一度にメモリに取り込むのではなく、要素を1つずつ処理することで、優れたメモリパフォーマンスが維持されます。 ツールを機能的なスタイルでリンクすることにより、コードの量を少なく抑え、一時変数を排除します。 インタープリターのオーバーヘッドが発生するforループやジェネレーターの使用よりも「ベクトル化された」ビルディングブロックを優先することで、高速性が維持されます。

def take(n, iterable):
    "Return first n items of the iterable as a list"
    return list(islice(iterable, n))

def prepend(value, iterator):
    "Prepend a single value in front of an iterator"
    # prepend(1, [2, 3, 4]) -> 1 2 3 4
    return chain([value], iterator)

def tabulate(function, start=0):
    "Return function(0), function(1), ..."
    return map(function, count(start))

def tail(n, iterable):
    "Return an iterator over the last n items"
    # tail(3, 'ABCDEFG') --> E F G
    return iter(collections.deque(iterable, maxlen=n))

def consume(iterator, n=None):
    "Advance the iterator n-steps ahead. If n is None, consume entirely."
    # Use functions that consume iterators at C speed.
    if n is None:
        # feed the entire iterator into a zero-length deque
        collections.deque(iterator, maxlen=0)
    else:
        # advance to the empty slice starting at position n
        next(islice(iterator, n, n), None)

def nth(iterable, n, default=None):
    "Returns the nth item or a default value"
    return next(islice(iterable, n, None), default)

def all_equal(iterable):
    "Returns True if all the elements are equal to each other"
    g = groupby(iterable)
    return next(g, True) and not next(g, False)

def quantify(iterable, pred=bool):
    "Count how many times the predicate is true"
    return sum(map(pred, iterable))

def padnone(iterable):
    """Returns the sequence elements and then returns None indefinitely.

    Useful for emulating the behavior of the built-in map() function.
    """
    return chain(iterable, repeat(None))

def ncycles(iterable, n):
    "Returns the sequence elements n times"
    return chain.from_iterable(repeat(tuple(iterable), n))

def dotproduct(vec1, vec2):
    return sum(map(operator.mul, vec1, vec2))

def flatten(list_of_lists):
    "Flatten one level of nesting"
    return chain.from_iterable(list_of_lists)

def repeatfunc(func, times=None, *args):
    """Repeat calls to func with specified arguments.

    Example:  repeatfunc(random.random)
    """
    if times is None:
        return starmap(func, repeat(args))
    return starmap(func, repeat(args, times))

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

def grouper(iterable, n, fillvalue=None):
    "Collect data into fixed-length chunks or blocks"
    # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return zip_longest(*args, fillvalue=fillvalue)

def roundrobin(*iterables):
    "roundrobin('ABC', 'D', 'EF') --> A D E B F C"
    # Recipe credited to George Sakkis
    num_active = len(iterables)
    nexts = cycle(iter(it).__next__ for it in iterables)
    while num_active:
        try:
            for next in nexts:
                yield next()
        except StopIteration:
            # Remove the iterator we just exhausted from the cycle.
            num_active -= 1
            nexts = cycle(islice(nexts, num_active))

def partition(pred, iterable):
    'Use a predicate to partition entries into false entries and true entries'
    # partition(is_odd, range(10)) --> 0 2 4 6 8   and  1 3 5 7 9
    t1, t2 = tee(iterable)
    return filterfalse(pred, t1), filter(pred, t2)

def powerset(iterable):
    "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
    s = list(iterable)
    return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))

def unique_everseen(iterable, key=None):
    "List unique elements, preserving order. Remember all elements ever seen."
    # unique_everseen('AAAABBBCCDAABBB') --> A B C D
    # unique_everseen('ABBCcAD', str.lower) --> A B C D
    seen = set()
    seen_add = seen.add
    if key is None:
        for element in filterfalse(seen.__contains__, iterable):
            seen_add(element)
            yield element
    else:
        for element in iterable:
            k = key(element)
            if k not in seen:
                seen_add(k)
                yield element

def unique_justseen(iterable, key=None):
    "List unique elements, preserving order. Remember only the element just seen."
    # unique_justseen('AAAABBBCCDAABBB') --> A B C D A B
    # unique_justseen('ABBCcAD', str.lower) --> A B C A D
    return map(next, map(operator.itemgetter(1), groupby(iterable, key)))

def iter_except(func, exception, first=None):
    """ Call a function repeatedly until an exception is raised.

    Converts a call-until-exception interface to an iterator interface.
    Like builtins.iter(func, sentinel) but uses an exception instead
    of a sentinel to end the loop.

    Examples:
        iter_except(functools.partial(heappop, h), IndexError)   # priority queue iterator
        iter_except(d.popitem, KeyError)                         # non-blocking dict iterator
        iter_except(d.popleft, IndexError)                       # non-blocking deque iterator
        iter_except(q.get_nowait, Queue.Empty)                   # loop over a producer Queue
        iter_except(s.pop, KeyError)                             # non-blocking set iterator

    """
    try:
        if first is not None:
            yield first()            # For database APIs needing an initial cast to db.first()
        while True:
            yield func()
    except exception:
        pass

def first_true(iterable, default=False, pred=None):
    """Returns the first true value in the iterable.

    If no true value is found, returns *default*

    If *pred* is not None, returns the first item
    for which pred(item) is true.

    """
    # first_true([a,b,c], x) --> a or b or c or x
    # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
    return next(filter(pred, iterable), default)

def random_product(*args, repeat=1):
    "Random selection from itertools.product(*args, **kwds)"
    pools = [tuple(pool) for pool in args] * repeat
    return tuple(random.choice(pool) for pool in pools)

def random_permutation(iterable, r=None):
    "Random selection from itertools.permutations(iterable, r)"
    pool = tuple(iterable)
    r = len(pool) if r is None else r
    return tuple(random.sample(pool, r))

def random_combination(iterable, r):
    "Random selection from itertools.combinations(iterable, r)"
    pool = tuple(iterable)
    n = len(pool)
    indices = sorted(random.sample(range(n), r))
    return tuple(pool[i] for i in indices)

def random_combination_with_replacement(iterable, r):
    "Random selection from itertools.combinations_with_replacement(iterable, r)"
    pool = tuple(iterable)
    n = len(pool)
    indices = sorted(random.randrange(n) for i in range(r))
    return tuple(pool[i] for i in indices)

def nth_combination(iterable, r, index):
    'Equivalent to list(combinations(iterable, r))[index]'
    pool = tuple(iterable)
    n = len(pool)
    if r < 0 or r > n:
        raise ValueError
    c = 1
    k = min(r, n-r)
    for i in range(1, k+1):
        c = c * (n - k + i) // i
    if index < 0:
        index += c
    if index < 0 or index >= c:
        raise IndexError
    result = []
    while r:
        c, n, r = c*r//n, n-1, r-1
        while index >= c:
            index -= c
            c, n = c*(n-r)//n, n-1
        result.append(pool[-1-n])
    return tuple(result)