入力文字列を考えると、私は他のすべての範囲内にある文字列 レーベンシュタイン距離 2.例えば、入力文字列が「AAA」で、アルファベットが[ある場合「」のセットを見つけるしたいと思い、 「B」]その後、我々は持っています:
{ 'baaa'、 'AAB'、 ''、 'AAAAA'、 'BAAB'、 'abbaa'、 'ABAA'、 'aaabb'、 'ABB'、 'AAAB'、 'アベバ'、 'A'、 ' AABB」、 'ババ'、 'baaab'、 'aabab'、 'aaaab'、 'abaaa'、 'aabaa'、 'bbaaa'、 'abaab'、 'AAAA'、 'baaaa'、 'BAB'、 'BBA' 、 'ABA'、 'aaaba'、 'BA'、 'aabba'、 'ABAB'、 'BAA'、 'AAA'、 'bbaa'、 'baaba'、 'AABA'、 'アバ'、 'AB'、 ' babaa '}
私はこれを行うには、コードを持っているが、それは非効率的です。ここでは、アルファベットと入力文字列aaaaaaaaaa
など、すべての印刷可能なASCII文字を使用しています。
import string
input_string = "a" * 10
f = (
lambda input_string, dist=2, i=0: dist * input_string[i - 1 :]
and {
k[:i] + char + k[i + w:]
for k in f(input_string, dist - 1)
for char in [""] + list(string.printable)
for w in (0, 1)
}
| f(input_string, dist, i + 1)
or {input_string}
)
f(input_string)
_
私は別の入力文字列でこれを何度も実行する必要があります。このコードは1631129個の異なる文字列を作るために私のデスクトップ上に現在2.9sかかります。誰もが非常に速く、それを作る方法を見ることができますか?
リーグテーブルこれまでに(使用して印刷可能なアルファベットなど):
私のコード:2.98秒±146ミリ
アランT.のコード:1.58秒±60.7ミリ。現在の勝者。
dDGのコード:1.85秒±28.4ミリ
可能な編集の全セットを生成することができる大きなスピードの改善を得ることができるとは思わない。
最初の編集後に同じ結果を生み出す文字列の再拡張を回避することで、35%から実行時間の50%を剃ることができます。これは、より高い編集距離とより大きな違いを与えるでしょう。改善レベルは、実際の文字列/単語(単一の繰り返し文字で構成されていない可能性がある)によっても依存します。
いずれにせよ、これが最適化された機能の機能です。
import string
from collections import deque
def makeEdits(S,count=1,charSet=None):
if charSet is None: charSet = string.printable
result = set([S])
expand = deque(result)
lastEdit = False
def addEdit(s):
if s in result: return
result.add(s)
if not lastEdit: expand.append(s)
for edit in range(count):
editing = expand.copy()
expand.clear()
lastEdit = edit == count-1
for eString in editing:
for i,char in enumerate(eString):
left,right = eString[:i],eString[i+1:]
addEdit(left+right) # deletion
for newChar in charSet:
addEdit(left+newChar+char+right) # insertions before
addEdit(left+newChar+right) # replacement
for newChar in charSet:
addEdit(eString+newChar) # insertion at end
return result
_
ラップトップ上のパフォーマンステスト:
from timeit import timeit
count = 1
input_string = "a" * 10
print('makeEdits()...')
print(len(makeEdits(input_string,2)))
t = timeit(lambda:makeEdits(input_string,2),number=count)
print(t)
print('f()...')
print(len(f(input_string)))
t = timeit(lambda:f(input_string),number=count)
print(t)
_
...
makeEdits()...
1631129
2.0302121050000004
f()...
1631129
3.145120027999999
_
String.ascii_letpersなどの文字セットが小さいほど、(より少ない文字列を生成することによって)パフォーマンス結果がかなり改善されます。
timeit(lambda:makeEdits(input_string,2,string.ascii_letters),number=count)
# 0.48669491199999015
len(makeEdits(input_string,2,string.ascii_letters)) # 433913
timeit(lambda:makeEdits(input_string,2,string.ascii_lowercase),number=count)
# 0.10699477299999671
len(makeEdits(input_string,2,string.ascii_lowercase)) # 104805
_
スペルチェッカーを作っている場合は、処理前にすべてを小文字に変換し、文字セットに含める単一の文字としてすべての特殊文字を扱うことができます。これにより、プログラムは、より小さな文字セットのパフォーマンスブーストを取得できるようになります(この場合は30倍高速)。文字列の前処理を加え、その後の結果の調整をいくつか追加する必要があります。