nozayasu-memo

プログラムのメモ

more_itertoolsでリストを小分けにする

大きめIDのリストを一定量の塊に分解しながら、DBに問い合わせをして後続の処理とかをしたいケースがあった

そんな時にmore_itertoolsを使ったら読みやすくなったという話

結果から、more_itertoolsのchunkedを使うと次のような書き方ができる

>>> from more_itertools import chunked
>>> ids = [0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> list(chunked(ids, 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8]]

chunkedってメソッドに元となるリストと塊の量を渡す、するとその量ごとのリストに分解してくれる

なにやるのかが明示的になったので、読みやすくなった

see also
erikrose/more-itertools: More routines for operating on iterables, beyond itertools More Itertools — more-itertools 3.2.0 documentation

これ見つける前に考えたこと

最初に考えたのは、内包表記とスライスで小分けにする方法

>>> ids = [0, 1, 2, 3, 4, 5, 6, 7, 8]
>>> [ids[i:i+3] for i in range(0, len(ids), 3)]
[[0, 1, 2], [3, 4, 5], [6, 7, 8]]

rangeの3つ目の引数、stepの内容をしらないと少し見慣れないかもしれない書き方だなと思った
あと自分で書いたけどイメージするのに、少し時間かかるのでもやっとしてた

see also
4. More Control Flow Tools — Python 3.6.2 documentation

というところまできて、ぐぐったらmore_itertoolsがすぐに見つかった

more_itertoolsを見つけたのと同時に、iterとzipを組み合わせて合わせて作る方法あるよーってのも見つかった。

>>> zip(*[iter(ids)]*3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]

ぱっとみ理解できない…
読み解くと同じイテレータオブジェクトを3つ生成して、それをZIPの引数として全て渡している
ZIPに渡す引数を同じものにすることで、自分自身を変更しながらとりだしてく
それによって渡した分だけの個数ごとに分割された状態となることが理解できた