python数组拆分后仍为数组 python数组分段_生成器


先来一段代码


squares


这是非常常见的一种通过append方法逐个增加元素创建列表的场景,而且通常我们可以理解为上述代码的时间复杂度为O(n)。这不能算错,但描述有点不准确,稍微理解Python列表类底层内容的小伙伴应该知道,列表类使用动态数组来存储数据。既然是动态数组就有动态调整数组大小的情况出现,在有些情况下数组容量大小调整耗时还是很可观的。有些资料为了描述准确,使用摊销的概念描述上述情况的时间复杂度,即上述代码行为在摊销情况下时间复杂度为O(n)。关于摊销的概念可自行搜索相关资料,文章后面也会给出参考资料[1]供大家阅读。

所以我们应该尽量避免动态数组的频繁大小调整,对于上面的例子,当n已知并且较大时,更好的实现方法是使用列表推导,即


squares = [i*i for i in range(1, n+1)]


实验可以证明列表推导的语法比不断增添数据来建表的速度明显更快,原因是列表推导在构建输出时已经将要占用的数组大小计算完毕,减小了动态数组大小的扩大次数。

其实,如果squares仅仅作为一个中间变量,并且后序如有遍历的需要,更好的方法是使用生成器来处理,即:


squares = (i*i for i in range(1, n+1))



类似的,在很多优秀的代码示例中经常看到,使用乘法操作初始化一张具有固定值、固定大小的列表,例如ans=[None]*10,这也非常具有Pythonic风格。这样做不但语法简单,而且比逐步构造效率高。

有时候我们还面临这么一种场景,需要将两个列表合并。按照上面的分析,同样存在动态数组容量大小调整影响效率的可能。在实践中,相对于重复调用append方法,我们更倾向于使用extend方法。extend效率的提升来源于更新列表的最终大小能够提前计算得到。假如需要追加的列表非常大,重复调用append方法时,底层动态数组会有多次调整大小的风险。若使用extend操作,最多执行一次调整动作。

注意,以下两种方式等效:


# data1与data2为列表数据类型,以下两种表示等效
data1.extend(data2)
data1 += data2