![](/img/trans.png)
[英]fastest way to check if all elements of a list of strings is in a string
[英]Length of all string in the list: the fastest way
我正在努力:
python3 -m timeit -c 'len("".join([str(x) for x in range(0, 999999)]))'
10 loops, best of 3: 330 msec per loop
python3 -m timeit -c 'sum((len(y) for y in [str(x) for x in range(0, 999999)]))
10 loops, best of 3: 439 msec per loop
為什么會這樣? 有沒有更快的方法?
PS假定將事先有一個字符串列表。
暫時忽略那個很小的時差,實際上兩種記憶方式之間存在巨大的時差。
sum((len(y) for y in [str(x) for x in range(0, 999999)]))
這將為每個數字創建一個字符串,並將其存儲在列表中。 然后,您可以使用生成器表達式遍歷該列表,並將長度加起來。 因此,基本上每個數字都有一個字符串,一個存儲所有字符串的列表,以及一個要添加的長度數字。
len(''.join([str(x) for x in range(0, 999999)]))
這將再次為每個數字創建一個字符串,並將其存儲在列表中。 然后,您將創建一個包含所有數字的巨大字符串。 之后,您調用in上的length(然后是O(1)調用)。 因此,您沒有要添加的數字(將長度加起來),但是確實有另一個長字符串再次將所有其他字符串組合在一起。
因此,即使速度更快,您也會浪費大量內存,這以后可能也會對性能產生影響。
為了改善所有這些,您應該考慮永久地創建盡可能少的東西。 不要使用列表推導,因為那樣會實際創建列表。 不要使用str.join
因為它需要一個列表並對其進行兩次迭代。
sum(len(str(x)) for x in range(0, 999999)))
現在,這仍然比len(''.join(…))
方法要慢,但是不會有太多的內存開銷。 實際上,它一次只會創建一個字符串對象,獲取其長度並將其添加到總和中。 然后可以立即收集字符串。
盡管這樣做仍然很慢的原因是,在生成器內部的每次迭代中都需要同時檢查len
和str
。 為了加快速度,請使用map
只查找兩次。 wim在評論中提出了一個非常好的建議:
sum(map(len, map(str, range(999999))))
對我來說,這實際上比len(''.join(…))
方法執行得更快。 我的時間安排是為了在我的答案中被提及:
62.36836282166257
50.54277449168785
58.24419845897603
40.3403849521618
使用IPython更好的基准測試表明情況比您想象的要糟:
>>> lst = [str(x) for x in range(0, 999999)]
>>> %timeit len("".join(lst))
100 loops, best of 3: 9.94 ms per loop
>>> %timeit sum(len(x) for x in lst)
10 loops, best of 3: 62.2 ms per loop
您會在這里看到兩個效果,Python中函數調用的開銷及其迭代的開銷。 "".join
沒有任何一個,因為它是在C中循環的單個方法調用。可以從map
獲得具有較少內存使用的中間性能:
>>> %timeit sum(map(len, lst))
10 loops, best of 3: 29.4 ms per loop
第一個(更快)版本對len
函數進行了1次調用,對join
進行了1次調用,對str
100k次調用。 查看第二行,您會發現len
和str
分別被調用10萬次,這在第二種情況下總共調用了大約兩倍的函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.