読者です 読者をやめる 読者になる 読者になる

タプルをreverseする

はじめに

先日、とある超レガシーなHTML(tableレイアウト)で書かれたサイトをスクレイピングしないと行けなくなったときに、取得したtd要素のうち、3の倍数番目だけが必要、なんて事がありました。

以前、初めてのPythonか何かを読んでスライスには3番目のパラメータがあるというのを思い出しました。なのでこのような場合だと[::3]としてやれば求めてるリストが得られるというわけですね。そんな感じで無事解決したのでした。


で、先日id:atsuoishimotoさんのツイートにこんなのがありました。

負の数値を指定するとシーケンスを降順に読み込んでくれるというのは気づきませんでした。
以前はあるタプルを降順にしたタプルを用意したい、といった場合に一度リストに変換してreverse()して再度タプルに変換する、なんてめんどくさいことしてましたが、これを使えば超ラクチンですね。後ろからn個飛ばしで、なんてこともできるし。

reverseと[::-1]どっちが速い?

reverseと[::-1]ではどちらが速いか気になったので調べてみました。

import cProfile

def list_re(ls):
    ls.reverse()

def list_sl(ls):
    result = ls[-1::-1]
    return result

def tpl_re(tpl):
    l = list(tpl)
    l.reverse()
    result = tuple(l)
    return result

def tpl_sl(tpl):
    result = tpl[-1::-1]
    return result

l1 = [i for i in range(1000000)] #リストを用意する
l2 = l1[:] #コピーを用意
tpl = tuple(l1) #タプルも用意

if __name__ == '__main__':
    cProfile.run("list_re(l1)")
    cProfile.run("list_sl(l2)")
    cProfile.run("tpl_re(tpl)")
    cProfile.run("tpl_sl(tpl)")

さっそく測ってみた

>>> 
         4 function calls in 0.005 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    0.005    0.005 <string>:1(<module>)
        1    0.000    0.000    0.005    0.005 test.py:5(list_re)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.005    0.005    0.005    0.005 {method 'reverse' of 'list' objects}


         3 function calls in 0.046 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.023    0.023    0.046    0.046 <string>:1(<module>)
        1    0.023    0.023    0.023    0.023 test.py:8(list_sl)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


         4 function calls in 0.078 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.035    0.035    0.078    0.078 <string>:1(<module>)
        1    0.040    0.040    0.043    0.043 test.py:12(tpl_re)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.003    0.003    0.003    0.003 {method 'reverse' of 'list' objects}


         3 function calls in 0.038 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.017    0.017    0.038    0.038 <string>:1(<module>)
        1    0.021    0.021    0.021    0.021 test.py:18(tpl_sl)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

リストはreverse使ったほうが圧倒的に速いですね。reverseは元のリストそのものを操作するからかな?リストはおそらくメソッドを使って処理したほうが効率がいいだろうと思われます。

それに対し、タプルの方はスライスを使って操作したほうが良さそうですね。まあ予想通りな感じですが。