coLinux日記

coLinuxはフリーソフトを種として、よろずのシステムとぞなれりける。

SimplePrograms で Python を学ぶ その15

2024-06-21 18:53:51 | Python
SimplePrograms - Python Wiki
https://wiki.python.org/moin/SimplePrograms

の 15番目のプログラムは、 itertools です。

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.

15行なのにコメント行が5行ですね。ファイルにして実行してみます。

$ ./prog-015.py
This is the first paragraph.
This is the second.
$

最後のコメント行通りの出力です。

まず、splitlines() メソッドの動きを見てみます。3重クオートによって生成された lines 変数は、

>>> lines
'\nThis is the\nfirst paragraph.\n\nThis is the second.\n'
>>>

で、splitlines() メソッドを使うと、

>>> lines.splitlines()
['', 'This is the', 'first paragraph.', '', 'This is the second.']
>>>

改行文字が区切りであり、空行が空の要素になるのですね。

また、join()は、

>>> print('X'.join('abcde'))
aXbXcXdXe
>>>
>>> print('X'.join(['ab','cd','ef']))
abXcdXef
>>>

なので試した例では、join()の引数が、文字列なら1文字づつ、配列なら要素毎に、'X'オブジェクトを挟んで結合するようです。

これは、
https://docs.python.org/ja/3/library/stdtypes.html?highlight=join#bytes.join
から、
「要素間のセパレータは、このメソッドを提供する bytes または bytearray オブジェクトとなります。」
だからですね。

各メソッドが分かったので、itertools を調べましょう。
https://docs.python.org/ja/3/library/itertools.html?highlight=itertools

このモジュールは APL を参考にしているので、複数要素からなるオブジェクトに対して複雑な繰り返しの操作を行うことのできるもののようです。

APLは古い記憶をたどると、確か
ι 12
で 1 , 2, 3, ... , 12 のベクトルが生成できて(つまりイテレータ)、さらに、
4 3 ρ ι 12
とすると、このベクトルを4行3列の2次元配列にしてくれる、という変わった言語だったと思います。
ちなみに、APLは特殊文字を多様するため現在使用するのは難しそうですが、
この言語、文字列配列変数の中身を変更して実行できる、のような特殊な機能満載なので、機会があればに深淵?を覗いてみるのも良いかもしれませんね。

今回は、そんなイテレータの中から、groupby()を使った例ですね。
https://docs.python.org/ja/3/library/itertools.html?highlight=itertools#itertools.groupby

groupby()の実際の動きは複雑そうですが、今回は
itertools.groupby(iterable, key=None)
の、 key が bool なので、 True または False を返すようです。試してみます。

>>> a
['', 'This is the', 'first paragraph.', '', 'This is the second.']
>>> for b, c in groupby(a, bool):
...        print(b, c)
...
False <itertools._grouper object at 0xb6a5bbb0>
True <itertools._grouper object at 0xb6a5bad8>
False <itertools._grouper object at 0xb6a5bbb0>
True <itertools._grouper object at 0xb6a5bad8>
>>>

groupby(a, bool) によって、配列 a の要素が 空文字なら False, 文字列なら True になるようです。
a の要素が 5 なのに、for ループは4回なのは、a の要素 1 と 2 が、連続して空文字でなかったので、
「key 関数の値が変わるたびに休止または新しいグループを生成します」から、一つの itertools._grouper オブジェクト内に 2つの要素をグループ化したようです。

それで、そのグループがjoin()によって' 'で連結されて、

'This is the first paragraph.'

になったのですね。例えばこんな感じです。

>>> aa
['ab', '', 'cde', '', '', 'fg', 'hij', 'klm']
>>> for b, c in groupby(aa, bool):
...        print(b,c)
...
True <itertools._grouper object at 0xb6971bc8>
False <itertools._grouper object at 0xb6a5bad8>
True <itertools._grouper object at 0xb6a5b9e8>
False <itertools._grouper object at 0xb6a5bad8>
True <itertools._grouper object at 0xb6a5b9e8>
>>> for b, c in groupby(aa, bool):
...        if b:
...           print(' '.join(c))
...
ab
cde
fg hij klm
>>>

連続した空行と連続した文字列はグループ化されて8要素が5グループに分類され、空行は False なので除かれ、最後の連続した3要素が ' ' 文字(空白文字)で連結されました。

itertools の奥は深そうですが、SamplePrograms にでてくるのが凄いですね。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする