見出し画像

【Python】SimplePrograms line 15 itertools

プログラム

15行プログラムです。
といっても、そのうちの5行がコメントですが。

from itertools import groupby
lines = '''
This is the
first paragraph.

This is the second.
'''.splitlines()
# Use itertools.groupby and bool to return groups of
# consecutive lines that either have content or don't.
for has_chars, frags in groupby(lines, bool):
    if has_chars:
        print (' '.join(frags))
# PRINTS:
# This is the first paragraph.
# This is the second.

実行結果

This is the first paragraph.
This is the second.

解説

itertools。

イテレータとは何か。

イテレータ(英語: iterator)とは、プログラミング言語において配列やそれに類似する集合的データ構造(コレクションあるいはコンテナ)の各要素に対する繰り返し処理の抽象化である。

https://ja.m.wikipedia.org/

であるらしい。

Pythonドキュメントには、「itertools」について次のようにあります。

効率的なループ実行のためのイテレータ生成関数

https://docs.python.org/ja/3/library/itertools.html

この「itertools」なるものにはいろいろな関数があるようですが、今回はそのうちの「groupby」を使っています。

itertools.groupby(iterable, key=None)

同じキーをもつような要素からなる iterable 中のグループに対して、キーとグループを返すようなイテレータを作成します。

https://docs.python.org/ja/3/library/itertools.html#itertools.groupby

どうも、よくわからん。
ソフトウェアのドキュメントというのは、何故こうもわかりにくいのだろう。宿命なのか(自戒も含む)。

「iterable」というのは配列のようなものです。「iterable」についてはこちらにも記載しました。

「イテレータ」というのは「iterableなもの」であって「__next__() メソッド」を持ちます。

「iterable」は複数のデータを持ちますが、「連続した同じ値をグルーピングする」というのが「groupby」です。

例えば。

「'AAAABBBCCDAABBB'」のような文字列をグルーピングすると次のようになります。

for k, g in groupby('AAAABBBCCDAABBB'):

    k|g
-----|--------------------
    A|['A', 'A', 'A', 'A']
    B|['B', 'B', 'B']
    C|['C', 'C']
    D|['D']
    A|['A', 'A']
    B|['B', 'B', 'B']

あるいは、「[1, 2, 2, 0, 0, 3, 3, 3, 2]」のようなlistをグルーピングするとこんな感じ。

for k, g in groupby([1, 2, 2, 0, 0, 3, 3, 3, 2]):

    k|g
-----|--------------------
    1|[1]
    2|[2, 2]
    0|[0, 0]
    3|[3, 3, 3]
    2|[2]

同じKeyが複数あらわれますが、関数「groupby」は、引数「iterable」がソートされていることを前提としています。

サンプルプログラムは、文字列をKey「bool」でグルーピングしていて、「bool」というのがちょっと意外。

確認してみると、次のようになりました。

for has_chars, frags in groupby(lines, bool):

has_chars|frags
---------|--------------------
    False|['']
     True|['This is the', 'first paragraph.']
    False|['']
     True|['This is the second.']

うーん。
まとめていろいろ確認してみた。

  • line15_list1.py  実行結果

####################
for k, g in groupby('AAAABBBCCDAABBB'):
type k=<class 'str'>
type g:<class 'itertools._grouper'>

    k|g
-----|--------------------
    A|['A', 'A', 'A', 'A']
    B|['B', 'B', 'B']
    C|['C', 'C']
    D|['D']
    A|['A', 'A']
    B|['B', 'B', 'B']


####################
for k, g in groupby('AAAABBBCCDAABBB', bool):
type k=<class 'bool'>
type g:<class 'itertools._grouper'>

    k|g
-----|--------------------
 True|['A', 'A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'D', 'A', 'A', 'B', 'B', 'B']


####################
for k, g in groupby('AAAABBBCCDAABBB', str):
type k=<class 'str'>
type g:<class 'itertools._grouper'>

    k|g
-----|--------------------
    A|['A', 'A', 'A', 'A']
    B|['B', 'B', 'B']
    C|['C', 'C']
    D|['D']
    A|['A', 'A']
    B|['B', 'B', 'B']


####################
for k, g in groupby([1, 2, 2, 0, 0, 3, 3, 3, 2], str):
type k=<class 'str'>
type g:<class 'itertools._grouper'>

    k|g
-----|--------------------
    1|[1]
    2|[2, 2]
    0|[0, 0]
    3|[3, 3, 3]
    2|[2]


####################
for k, g in groupby([1, 2, 2, 0, 0, 3, 3, 3, 2], int):
type k=<class 'int'>
type g:<class 'itertools._grouper'>

    k|g
-----|--------------------
    1|[1]
    2|[2, 2]
    0|[0, 0]
    3|[3, 3, 3]
    2|[2]


####################
for k, g in groupby([1, 2, 2, 0, 0, 3, 3, 3, 2], bool):
type k=<class 'bool'>
type g:<class 'itertools._grouper'>

    k|g
-----|--------------------
 True|[1, 2, 2]
False|[0, 0]
 True|[3, 3, 3, 2]


####################
for k, g in groupby([1, 2, 2, 0, 0, 3, 3, 3, 2]):
type k:<class 'int'>
type g:<class 'itertools._grouper'>

    k|g
-----|--------------------
    1|[1]
    2|[2, 2]
    0|[0, 0]
    3|[3, 3, 3]
    2|[2]

ライブラリの動作を隅隅まで見通し難い。

Pythonドキュメントにはレシピもあります。


前記「line15_list1.py」はこちらからダウンロードできます。

いいなと思ったら応援しよう!