pythonのitertoolsメモ

バージョン: python3.3
参考: http://docs.python.org/3/library/itertools.html
itertoolsのpythonによる実装が書いてあるので勉強になります.


・itertools.accumulate(iterable[, func])

In [2]: it = itertools.accumulate([1,2,3])

In [3]: for i in it:
   ...:     print(i)
   ...:
1
3   # 1+2
6   # 3+3

In [6]: it = itertools.accumulate([1,2,3],lambda x,y: x*y)

In [7]: for i in it:
   ...:     print(i)
   ...:
1
2    # 1*2
6    # 2*3

python3.2で追加されてfuncは3.3から指定できるようになったらしい.


・itertools.chain(*iterables)
iterableなアイテムをつなげたイテレータを返す

In [10]: it = itertools.chain([1,2,3],['a','b','c'])

In [11]: for i in it:
   ....:     print(i)
   ....:
1
2
3
a
b
c


・itertools.chain.from_iterable(iterable)
iteratools.chain(*iterables)と似てるけど引数が一つのリスト

In [13]: it = itertools.chain.from_iterable([[1,2,3],['a','b','c']])

In [14]: for i in it:
   ....:     print(i)
   ....:
1
2
3
a
b
c


・itertools.combinations(iterable,r)
長さrの組み合わせを返します

In [15]: it = itertools.combinations([1,2,3],2)

In [16]: for i in it:
   ....:     print(i)
   ....:
(1, 2)
(1, 3)
(2, 3)


・itertools.combinations_with_replacement(iterable,r)
重複を含めた長さrの組み合わせを返します

In [17]: it = itertools.combinations_with_replacement([1,2,3],2)

in [18]: for i in it:
   ....:     print(i)
   ....:
(1, 1)
(1, 2)
(1, 3)
(2, 2)
(2, 3)
(3, 3)


・itertools.compress(data,selectors)
selectorsがTrueの要素のdataについてのイテレータを返します
例を見た方が早い.

In [21]: it = itertools.compress(['A','B','C'],[True,False,True])

In [22]: for i in it:
   ....:     print(i)
   ....:
A
C

python3.1で追加


・itertools.count(start=0,step=1)
startから初めてstepずつ増えてくiteratorを返します

In [27]: def generator():
   ....:     for i in range(10):
   ....:         yield i

In [30]: for i,v in zip(generator(),itertools.count()):
    print("{0}:{1}".format(i,v))
   ....:
0:0
1:1
2:2
3:3
4:4
5:5
6:6
7:7
8:8
9:9

ちなみにpython3ではzip()がpython2のitertools.izip()に相当します.


・itetools.cycle(iterable)
iterableなものを巡回するイテレータを返します.

In [2]: it = itertools.cycle([1,2,3])

In [3]: next(it)
Out[3]: 1

In [4]: next(it)
Out[4]: 2

In [5]: next(it)
Out[5]: 3

In [6]: next(it)
Out[6]: 1

In [7]: next(it)
Out[7]: 2

In [8]: next(it)
Out[8]: 3
||<k


・itertools.dropwhile(predicate,iterable)
先頭から見ていって初めてpredicateがFalseになる要素の前までの要素を除いたイテレータを返します
>|python|
In [12]: it = itertools.dropwhile(lambda x : x < 5, [1,2,4,2,5,3,6,2])

In [13]: for i in it:
   ...:     print(i)
   ...:
5
3
6
2


・itertools.filterfalse(predicate,iterable)
iterableをpredicateでフィルターした結果を返すイテレータを返します

In [14]: it = itertools.filterfalse(lambda x : x < 5, [1,2,4,2,5,3,6,2])

In [15]: for i in it:
   ....:     print(i)
   ....:
5
6


・itetools.groupby(iterable,key=None)
連続する要素をkeyで比較して一致した場合には一つにまとめる.keyを指定しない場合は同じ要素が連続した場合一つにまとめます
uniqコマンド的な.
戻り値は2つあって,1つがキー,もう一つが連続する要素をまとめたもの(これもイテレータ).

In [24]: for k,g in itertools.groupby('AAABDDDCCC'):
    print(k)
    print(list(g))
   ....:
A
['A', 'A', 'A']
B
['B']
D
['D', 'D', 'D']
C
['C', 'C', 'C']


・itertools.islice(iterable,stop), itertools.islice(iterable,start,stoip[,step])
iterableな要素の中で選択した範囲を返すイテレータを返します

In [25]: it = itertools.islice('ABCDEFG',1,5,2)

In [26]: for i in it:
   ....:     print(i)
   ....:
B
D


・itertools.permutation(iterable,r=None)
長さrの順列を返します.rを指定しない場合はiterableの長さがrになります.

In [27]: it = itertools.permutations('ABC')

In [28]: for i in it:
   ....:     print(i)
   ....:
('A', 'B', 'C')
('A', 'C', 'B')
('B', 'A', 'C')
('B', 'C', 'A')
('C', 'A', 'B')
('C', 'B', 'A')


・itertools.product(*iterables,repeat=1)
直積を返します.product([0,1],repeat=3)はproduct([0,1],[0,1],[0,1])と同じ意味.

In [34]: it = itertools.product([0,1],['x','y'])

In [35]: for i in it:
   ....:     print(i)
   ....:
(0, 'x')
(0, 'y')
(1, 'x')
(1, 'y')


・itertools.repeat(object[, times])
objectをtimes回繰り返すイテレータを返します.timesを指定しない場合無限リストになります.
主な使い方としてはmap()やzip()に一定値を与えるのに使うみたい

In [37]: list(map(pow,range(10),itertools.repeat(2)))
Out[37]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]


・itertools.starmap(function,iterable)
iterableな各要素についてfunctionで計算した結果のイテレータを返します.
map()に似てるけど要はmapの引数が既にzip化されてるときに使います.

In [46]: [i for i in itertools.starmap(pow,[(2,5),(3,2),(10,3)])]
Out[46]: [32, 9, 1000]

これと等価

In [50]: x = zip([2,3,10],[5,2,3])

In [51]: for i in itertools.starmap(pow,x):
    print(i)
    ....:
32
9
1000

ちなみにmap()を使うなら

In [52]: [i for i in map(pow,[2,3,10],[5,2,3])]
Out[53]: [32, 9, 1000]


・itertools.takewhile(predicate,iterable)
先頭から見ていってpredicateが初めてFalseになるまでの要素を返すイテレータを返す.

In [64]: it = itertools.dropwhile(lambda x:x<5, [1,2,3,5,2,1])

In [65]: for i in it:
   ....:     print(i)
   ....:
5
2
1


・itertools.tee(iterable,n = 2)
1つのiterableからn個のイテレータを返します.nのデフォルトは2です.

In [66]: it1,it2 = itertools.tee([1,2,3])

In [67]: for i in it1:
   ....:     print(i)
   ....:
1
2
3

In [68]: for i in it2:
   ....:     print(i)
   ....:
1
2
3

teeで複数イテレータを作ったあと元のiterableを操作することはイテレータが勝手に進んだりするのやめましょう.イテレータを複数作るのに比べてteeのメリットは何かというと,teeを使った方がバッファリングをするためI/Oが少なくなり,動作が速くなる可能性があります.逆に言うとメモリをよく消費します.このことはteeの実装を見ると分かります.

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
                newval = next(it)       # fetch a new value and
                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から一つイテレータを作って,それからn個のdequeを用意して,いずれかのteeの戻り値のイテレータがが新しい値を取り出す度に他のdequeに値を追加していきます.


・itertools.zip_longest(*iterables,fillvalue=None)
zip()に似ていますが,zipと違うのはiterablesの長さが異なる場合,短いiterableが
終わるとそれ以降対応する場所はfillvalueで埋められます.

In [69]: it = itertools.zip_longest(['A','B','C','D'],[1,2],fillvalue='-')

In [70]: for i in it:
   ....:     print(i)
   ....:
('A', 1)
('B', 2)
('C', '-')
('D', '-')