Adding Thousand Separators using itertools
この問題が面白そうだなと思い、私もPythonで挑戦してみました。目的は、数字にコンマを振ることです。
「Python のジェネレータ (2)」に引き続き、ジェネレータに慣れるための練習。o(+_+)o どかにまた例題はないかと散策していたら、「数字にコンマを振る」が良さげ。
Python のジェネレータ (3) - 数字にコンマを振る | すぐに忘れる脳みそのためのメモ
当初は、先日Schemeでコーディングしたこの問題と同様、継続渡し形式でコードを書く良い問題であるのではないかと思っていました。しかし、これが大変難しい。そのため、イテレータ、itertoolsモジュールを積極的に使う方針としてみました。出来上がったコードは次のようなものです。Python3.0を使っています。
from itertools import chain, cycle, islice def thousand_separated(n): return ''.join(chain(*zip(reversed(str(n)), cycle(('', '', ',')))))[::-1].lstrip(',')
うーん、いいのか悪いのか。最後にstr.lstrip()で整形しているのが悲しいところ。
テストコードを含めたコードとその結果を以下に。数値の生成にもitertoolsで。
thousand_separated.py: #!/usr/local/bin/python3.0 -t from itertools import chain, cycle, islice def thousand_separated(n): return ''.join(chain(*zip(reversed(str(n)), cycle(('', '', ',')))))[::-1].lstrip(',') if __name__ == '__main__': for i in range(20): n = int(''.join(islice(cycle('1234567890'), i+1))) print('%27s' % thousand_separated(n))
> ./thousand_separated.py 1 12 123 1,234 12,345 123,456 1,234,567 12,345,678 123,456,789 1,234,567,890 12,345,678,901 123,456,789,012 1,234,567,890,123 12,345,678,901,234 123,456,789,012,345 1,234,567,890,123,456 12,345,678,901,234,567 123,456,789,012,345,678 1,234,567,890,123,456,789 12,345,678,901,234,567,890
さて、関数内で何が起こっているかをPostScriptで可視してみました。目的は数値にコンマを挿入することでした。
これではよく分かりませんね。コンマの行にも罫線を追加してやります。
空のセルを明示するために空文字列('')を入れてみます。また、コンマも文字列とします(',')。何か見えてきましたね。
コンマは最後の桁から3桁ずつ数えるのでした。左右反転してみましょう。
同じ列のセルは上から読むと決め、上下の行のズレを補正してみましょう。2行の行列のようになりますね。
なるほどこの2つの行をイテレータとして作成してやり、合成すれば良さそうです。では、str(n)で数値を文字列に変換します。
次に、reversed()を用いて文字列を反転します。ここからはイテレータの世界となります。これで数値側のイテレータの準備は完了です。
さて、今度はカンマ側のイテレータを見てみます。まず、('', '', ',')としてタプルを作成します。タプルもイテレータとして扱うことが出来ます。
これを、itertools.cycle()を用いて無限に反復させます。
反転させた数値のイテレータとカンマ側のイテレータを合成します。合成にはzip()を用います。
カンマ側のイテレータは無限に要素を返しますが、zip()は与えられたイテレータの一つが終了した場合、反復を終了します。言い換えれば、最も短いイテレータに合わせ、切りそろえてくれるような働きをします。
zip()の結果は行列のように見えますよね。実際、これは先に挙げた行列を転置した行列となっています。
さらにitertools.chain()を用いて、一次元のイテレータに変換します。
このイテレータを''.join()すると、空の文字が押しつぶされたような状態になります。カンマの引用符も消してしまいましょう。
最後にスライスを用いて文字列を反転させます。
入力した数値の桁数が3で割り切れる場合、先頭にコンマがついてします。そのため、str.lstrip()で削除しています。