[英]How is str.find so fast?
我有一個較早的問題,我在迭代字符串和使用切片時尋找 substring。 事實證明,這對性能來說是一個非常糟糕的主意。 str.find
要快得多。 但我不明白為什么?
import random
import string
import timeit
# Generate 1 MB of random string data
haystack = "".join(random.choices(string.ascii_lowercase, k=1_000_000))
def f():
return [i for i in range(len(haystack)) if haystack[i : i + len(needle)] == needle]
def g():
return [i for i in range(len(haystack)) if haystack.startswith(needle, i)]
def h():
def find(start=0):
while True:
position = haystack.find(needle, start)
if position < 0:
return
start = position + 1
yield position
return list(find())
number = 100
needle = "abcd"
expectation = f()
for func in "fgh":
assert eval(func + "()") == expectation
t = timeit.timeit(func + "()", globals=globals(), number=number)
print(func, t)
結果:
f 26.46937609199813
g 16.11952730899793
h 0.07721933699940564
f
和g
很慢,因為它們檢查是否可以在haystack
的每個可能位置找到needle
,從而導致O(nm)
的復雜性。 f
較慢,因為創建新字符串 object 的切片操作(正如 Barmar 在評論中指出的那樣)。
h
很快,因為它可以跳過很多位置。 例如,如果沒有找到needle
串,則只執行一次find
。 內置find
function 在 C 中進行了高度優化,因此比解釋的純 Python 代碼更快。 此外, find
function 使用一種稱為Crochemore 和 Perrin 的雙向算法的高效算法。 當字符串比較大時,該算法比在haystack
的每個可能位置都搜索needle
快得多。 相關的 CPython 代碼可在此處獲得。
如果出現的次數比較少,你的實現應該已經很好了。 否則,最好使用基於可能是KMP 算法的 CPTW 算法的自定義變體,但在純 Python 中這樣做會非常低效。 您可以在 C 或使用 Cython 中執行此操作。 話雖這么說,這不是一件容易的事,也不是很好維護。
內置的Python函數是在C中實現的,這樣可以快很多。 不可能使 function 在使用 Python 時性能一樣好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.