検索の速度は、いくつかの要因によって異なります。
- 文字列の長さ
- 1回限りのキャラクターが存在しない位置
- この位置の後の文字列のサイズ
- 文字列に出現するさまざまな文字の数
。
次のコードでは、最初に
、2つの文字列から、 という名前の1回限り発生する文字のグループを使用して文字列s
を定義し、連結します。
ここで: random.choice()
unik
s1
s2
s1 + s2
s1
nwo
一度だけ出現する文字がない長さの文字列です
s2
nwi
1回限りの文字が含まれる長さの文字列です
。
#### creation of s from s1 and s2 #########
from random import choice
def without(u,n):
letters = list('abcdefghijklmnopqrstuvwxyz')
for i in xrange(n):
c = choice(letters)
if c not in unik:
yield c
def with_un(u,n):
letters = list('abcdefghijklmnopqrstuvwxyz')
ecr = []
for i in xrange(n):
c = choice(letters)
#ecr.append('%d %s len(letters) == %d' % (i,c,len(letters)))
yield c
if c in unik:
letters.remove(c)
#print '\n'.join(ecr)
unik = 'ekprw'
nwo,nwi = 0,500
s1 = ''.join(c for c in without(unik,nwo))
s2 = ''.join(c for c in with_un(unik,nwi))
s = s1 + s2
if s1:
print '%-27ss2 : %d chars' % ('s1 : %d chars' % len(s1),len(s2))
for el in 'ekprw':
print ('s1.count(%s) == %-12ds2.count(%s) == %d'
% (el,s1.count(el),el,s2.count(el)))
others = [c for c in 'abcdefghijklmnopqrstuvwxyz' if c not in unik]
print 's1.count(others)>1 %s' % all(s1.count(c)>1 for c in others)
else:
print "s1 == '' len(s2) == %d" % len(s2)
for el in 'ekprw':
print (' - s2.count(%s) == %d'
% (el,s2.count(el)))
print 'len of s == %d\n' % len(s)
次に、ベンチマークがあります。数値を
変えると、速度への影響がわかります。nwo
nwi
### benchmark of three solutions #################
from time import clock
# Janne Karila
from collections import Counter, OrderedDict
class OrderedCounter(Counter, OrderedDict):
pass
te = clock()
c = OrderedCounter(s)
rjk = (item for item, count in c.iteritems() if count == 1).next()
tf = clock()-te
print 'Janne Karila %.5f found: %s' % (tf,rjk)
# eyquem
te = clock()
candidates = set(s)
li = []
for x in s:
if x in candidates:
li.append(x)
candidates.remove(x)
elif x in li:
li.remove(x)
rey = li[0]
tf = clock()-te
print 'eyquem %.5f found: %s' % (tf,rey)
# TyrantWave
te = clock()
rty = (a for a in s if s.count(a) == 1).next()
tf = clock()-te
print 'TyrantWave %.5f found: %s' % (tf,rty)
。
いくつかの結果
nullの長さの場合、 nwo s1
=0およびnwi=50:
s1 == '' len(s2) == 50
- s2.count(e) == 1
- s2.count(k) == 1
- s2.count(p) == 1
- s2.count(r) == 1
- s2.count(w) == 1
len of s == 50
Janne Karila 0.00077 found: e
eyquem 0.00013 found: e
TyrantWave 0.00005 found: e
TyrantWaveのソリューションは、最初の1つの文字が文字列の最初の位置ですばやく検出されるため、より高速です。
。
nwo=300およびnwi=50の場合( 1回限り発生する文字の出現はの構築中に保持されなかったため、
以降は401文字。関数without()を参照)s1
s1
s1 : 245 chars s2 : 50 chars
s1.count(e) == 0 s2.count(e) == 1
s1.count(k) == 0 s2.count(k) == 1
s1.count(p) == 0 s2.count(p) == 1
s1.count(r) == 0 s2.count(r) == 1
s1.count(w) == 0 s2.count(w) == 1
s1.count(others)>1 True
len of s == 295
Janne Karila 0.00167 found: e
eyquem 0.00030 found: e
TyrantWave 0.00042 found: e
今回のTyrantWaveのソリューションは、最初の部分のすべての文字の出現をカウントする必要があるため、つまり、1回限りの文字がない(2番目の部分にある)ため、私のソリューションよりもs
長くs1
なりs2
ます
。私のソリューションでより短い時間を取得nwo
します。nwi
。
nwo=300およびnwi=5000の場合
s1 : 240 chars s2 : 5000 chars
s1.count(e) == 0 s2.count(e) == 1
s1.count(k) == 0 s2.count(k) == 1
s1.count(p) == 0 s2.count(p) == 1
s1.count(r) == 0 s2.count(r) == 1
s1.count(w) == 0 s2.count(w) == 1
s1.count(others)>1 True
len of s == 5240
Janne Karila 0.01510 found: p
eyquem 0.00534 found: p
TyrantWave 0.00294 found: p
の長さが長くなるとs2
、TyrantWaveのソリューションが再び優れたものになります。
。
あなたが望むものを結論付ける
。
編集
ローマの素晴らしいアイデア!
ベンチマークにRomanのソリューションを追加したところ、勝ちました。
私はまた、彼の解決策を改善するためにいくつかの小さな変更を加えました。
# Roman Fursenko
srf = s[:]
te = clock()
while srf != "":
slen0 = len(srf)
ch = srf[0]
srf = srf.replace(ch, "")
slen1 = len(srf)
if slen1 == slen0-1:
rrf = ch
break
else:
rrf = "No answer"
tf = clock()-te
print 'Roman Fursenko %.6f found: %s' % (tf,rrf)
# Roman Fursenko improved
srf = s[:]
te = clock()
while not(srf is ""):
slen0 = len(srf)
srf = srf.replace(srf[0], "")
if len(srf) == slen0-1:
rrf = ch
break
else:
rrf = "No answer"
tf = clock()-te
print 'Roman improved %.6f found: %s' % (tf,rrf)
print '\nindex of %s in the string : %d' % (rty,s.index(rrf))
。
結果は次のとおりです。
。
s1 == '' len(s2) == 50
- s2.count(e) == 1
- s2.count(k) == 1
- s2.count(p) == 1
- s2.count(r) == 1
- s2.count(w) == 1
len of s == 50
Janne Karila 0.0032538 found: r
eyquem 0.0001249 found: r
TyrantWave 0.0000534 found: r
Roman Fursenko 0.0000299 found: r
Roman improved 0.0000263 found: r
index of r in the string : 1
s1 == '' len(s2) == 50
- s2.count(e) == 1
- s2.count(k) == 0
- s2.count(p) == 1
- s2.count(r) == 1
- s2.count(w) == 1
len of s == 50
Janne Karila 0.0008183 found: a
eyquem 0.0001285 found: a
TyrantWave 0.0000550 found: a
Roman Fursenko 0.0000433 found: a
Roman improved 0.0000391 found: a
index of a in the string : 4
>>
s1 : 240 chars s2 : 50 chars
s1.count(e) == 0 s2.count(e) == 1
s1.count(k) == 0 s2.count(k) == 0
s1.count(p) == 0 s2.count(p) == 1
s1.count(r) == 0 s2.count(r) == 1
s1.count(w) == 0 s2.count(w) == 1
s1.count(others)>1 True
len of s == 290
Janne Karila 0.0016390 found: e
eyquem 0.0002956 found: e
TyrantWave 0.0004112 found: e
Roman Fursenko 0.0001428 found: e
Roman improved 0.0001277 found: e
index of e in the string : 242
s1 : 241 chars s2 : 5000 chars
s1.count(e) == 0 s2.count(e) == 1
s1.count(k) == 0 s2.count(k) == 1
s1.count(p) == 0 s2.count(p) == 1
s1.count(r) == 0 s2.count(r) == 1
s1.count(w) == 0 s2.count(w) == 1
s1.count(others)>1 True
len of s == 5241
Janne Karila 0.0148231 found: r
eyquem 0.0053283 found: r
TyrantWave 0.0030166 found: r
Roman Fursenko 0.0007414 found: r
Roman improved 0.0007230 found: r
index of r in the string : 250
私はRomanのコードのおかげで何かを学びました:
s.replace()
新しい文字列を作成し、そのため、それは遅い方法だと思いました。
しかし、どのような理由で、それは本当に速い方法かわかりません。
。
編集2
Oinの解決策は最悪です:
# Oin
from operator import itemgetter
seen = set()
only_appear_once = dict()
te = clock()
for i, x in enumerate(s):
if x in seen and x in only_appear_once:
only_appear_once.pop(x)
else:
seen.add(x)
only_appear_once[x] = i
fco = min(only_appear_once.items(),key=itemgetter(1))[0]
tf = clock()-te
print 'Oin %.7f found: %s' % (tf,fco)
結果
s1 == '' len(s2) == 50
Oin 0.0007124 found: e
Janne Karila 0.0008057 found: e
eyquem 0.0001252 found: e
TyrantWave 0.0000712 found: e
Roman Fursenko 0.0000335 found: e
Roman improved 0.0000335 found: e
index of e in the string : 2
s1 : 237 chars s2 : 50 chars
Oin 0.0029783 found: k
Janne Karila 0.0014714 found: k
eyquem 0.0002889 found: k
TyrantWave 0.0005598 found: k
Roman Fursenko 0.0001458 found: k
Roman improved 0.0001372 found: k
index of k in the string : 246
s1 : 236 chars s2 : 5000 chars
Oin 0.0801739 found: e
Janne Karila 0.0155715 found: e
eyquem 0.0044623 found: e
TyrantWave 0.0027548 found: e
Roman Fursenko 0.0007255 found: e
Roman improved 0.0007199 found: e
index of e in the string : 244