前回(2008/08/22のエントリ)は、イテレータを引数にするuniqをPythonで書いてみる、という話でした。
今回は、リストをインプレースで修正する(破壊的な)uniqを書いてみるというお話。
書こうと思えばどうとでも書けるので、3つほど書いてみました。
def uniqit(seq):
if len(seq) <= 1:
return
i = 0
for q in seq[1:]:
if q != seq[i]:
i += 1
seq[i] = q
del seq[i + 1:]
def uniqit2(seq):
if len(seq) <= 1:
return
r = [ seq[0] ]
r.extend(q for p, q in zip(seq, seq[1:]) if q != p)
seq[:] = r
def uniqit3(seq):
if len(seq) <= 1:
return
i = 1
while i < len(seq):
if seq[i] == seq[i - 1]:
seq.pop(i)
else:
i += 1
で、これをランダムな整数のリストをソートしたものに適用してみる、というテストをしました。
a = [ random.randint(0, 1000) for _ in xrange(5000) ]
a.sort()
t0 = time.time()
for _ in xrange(100):
b = a[:]
uniqitなんたら(b)
t1 = time.time()
print t1 - t0
ここでクイズ。どれが一番速かったでしょうか。
答え。
・・・は示しませんので、ご自分でお試しください。ちなみに、最速と最遅では、かかる時間は1桁違いました。
蛇足ながら、以前のエントリで書いた、イテレータを引数とするuniqを使っても、当然同じことができます。
import itertools
def iuniq(enu):
ps, qs = itertools.tee(enu, 2)
yield ps.next()
for p, q in itertools.izip(ps, qs):
if p != q:
yield p
def uniqit4(seq):
if len(seq) <= 1:
return
seq[:] = [ v for v in iuniq(seq) ]
上述の3つと比べると、最速のものよりは遅いけれど、それ以外よりは速い、という結果でした。
なかなかやるなあ(自己満足)。