我尝试着:
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)]))
这将再次为每个数字创建一个字符串并将其存储在列表中.然后你创建一个包含所有数字的巨大字符串.然后你调用长度(然后是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