Skip to main content
 首页 » 编程设计

python之列表中所有字符串的长度 : the fastest way

2025年05月04日30cloudgamer

我正在尝试:

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 

为什么会这样?有没有更快的方法?

附言假定字符串列表将提前。

请您参考如下方法:

暂时忽略那个相当小的时间差异,您的两种方式在内存中实际上存在巨大差异。

sum((len(y) for y in [str(x) for x in range(0, 999999)])) 

这将为每个数字创建一个字符串并将其存储在列表中。然后使用生成器表达式循环遍历该列表并对长度求和。所以基本上每个数字都有一个字符串,一个存储所有字符串的列表,以及一个为长度添加的数字。

len(''.join([str(x) for x in range(0, 999999)])) 

这将再次为每个数字创建一个字符串并将其存储在列表中。然后你创建一个包含所有数字的巨大字符串。之后,您调用 length on in(然后是 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