簡體   English   中英

列表中所有字符串的長度:最快的方法

[英]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(…))方法要慢,但是不會有太多的內存開銷。 實際上,它一次只會創建一個字符串對象,獲取其長度並將其添加到總和中。 然后可以立即收集字符串。

盡管這樣做仍然很慢的原因是,在生成器內部的每次迭代中都需要同時檢查lenstr 為了加快速度,請使用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次調用。 查看第二行,您會發現lenstr分別被調用10萬次,這在第二種情況下總共調用了大約兩倍的函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM