銀月の符号

Python 使い見習いの日記・雑記

N 個の組

L[0:2], L[1:3], L[2:4] …のような値を返すイテレータについてのメモ。ほぼ itertools ライブラリドキュメントのレシピ のまま。

L[0:2], L[1:3], L[2:4] … のようなイテレータ

レシピにそのものが載っていたので転載。

from itertools import *

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

L[0:n], L[1:n+1], L[2:n+2] … のようなイテレータ

さきほどの pairwise と consume, repeatfunc というレシピらを参考に作成してみた。

今、疑問に思っている点は値の読み捨てに for 文、 for _ in xrange(n): next(it) ではなく collections.deque を使う理由について。こちらのほうが早いのだろうか? CPython の collections.deque は C 実装なので for 文より早い、とか? 後でベンチとってみようっと。

import itertools
import collections

def setwise(iterable, n=2):
    "s -> (s0,s1, ...), (s1,s2,...), (s2,s3,...), ..."
    its = itertools.tee(iterable, n)
    for i, it in enumerate(its):
        collections.deque(
                itertools.imap(next, itertools.repeat(it, i)),
                maxlen=0)
    return itertools.izip(*its)
使用例、連続する値を見つける

setwise を用いて整数値イテレータブルから、連続する値を見つけてみる。 itertools.ifilter 併用。

>>> from itertools import ifilter, izip, count, starmap
>>> from operator import eq
>>> def is_consecutive_numbers(nums):
...   it = iter(nums)
...   num = next(it)
...   return all(starmap(eq, izip(it, count(num + 1))))
...
>>> data = [1,  4,5,  9,10,11,  16,17,18,19]
>>> for n in ifilter(is_consecutive_numbers, setwise(data, 2)):
...   print n
...
(4, 5)
(9, 10)
(10, 11)
(16, 17)
(17, 18)
(18, 19)
>>> for n in ifilter(is_consecutive_numbers, setwise(data, 3)):
...   print n
...
(9, 10, 11)
(16, 17, 18)
(17, 18, 19)

別解、 itertools.groupby 併用。

>>> from itertools import groupby, imap
>>> from operator import itemgetter
>>> data = [1,  4,5,  9,10,11,  16,17,18,19]
>>> for k, g in groupby(enumerate(data), lambda (i,x):i-x):
...   for n in setwise(imap(itemgetter(1), g), 2):
...     print n
...
(4, 5)
(9, 10)
(10, 11)
(16, 17)
(17, 18)
(18, 19)
>>> for k, g in groupby(enumerate(data), lambda (i,x):i-x):
...   for n in setwise(imap(itemgetter(1), g), 3):
...     print n
...
(9, 10, 11)
(16, 17, 18)
(17, 18, 19)

L[n*0:n*1], L[n*1:n*2], L[n*2:n*3] … のようなイテレータ

これも載っているので、ついでに転載。

from itertools import *

def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return izip_longest(fillvalue=fillvalue, *args)