リストの要素削除で唸る
discrepancyの測定(まとまったら別に記事でまとめる)で、Pythonのリストを使って系列を表現したプログラムを作成している。その中で、「予め昇順にソートしてある整数値のリスト末尾にある要素と同じ要素を全て取り除く」処理を書いていた。
つまり、a = [1, 3, 4, 6, 7, 7, 8, 10, 10]
のようなソート済みのリストがあった場合に、末尾にある要素10に注目して、この要素と同じものを全て取り除くという処理だ。
最初に浮かんだのは、
tail = a[-1]
while a[-1] == tail:
del a[-1]
みたいなwhile文による削除方法だ。しかし、これはaの要素が空になるとエラーになる。考えてみれば当たり前なのだが、aの中身が空っぽの場合は、a[-1]なんて要素が無いからだ。対処方法はいろいろ考えられるのだが、別の場所でこの削除した後の要素数が必要になるので、それを変数elementsに入れて記録してみた。
elements = len(a)
tail = a[-1]
while (elements > 0) and (a[-1] == tail):
del a[-1]
elements -= 1
動くには動くのだが、もう少し簡単に書けない?と考えて、以下のような手を思いついた。
del a[ -a.count(a[-1]): ]
おお、これはスッキリ。早速、要素数6万程度のデータ数本で実験をしてみたら、上の2つのプログラムが1秒程度で終わった処理が、一番下の書き方だと100秒程度かかるようになってしまった。
簡単に、簡潔に書き直したハズがその部分だけで100倍も遅くなるのか。
幾つか試験的なプログラムを書いてみて、リストの全体に対する処理(countやlenなど)は要素数が増えてくるととても重い処理になるようだ。そのため、それ以外の部分が簡潔に書けていたとしても、処理速度は速くなるどころか逆に遅くなる場合もある。
特に今回は、このリストを処理する部分以外があまり負荷の大きくない処理だったため、この部分の処理速度差が露骨に表れたのではないかと推測している。
この辺りの匙加減が良くわからない辺りが、自分はまだPythonに慣れていない証拠だ。