Python中如何去除三重嵌套for循环?求代码优化方案
三重嵌套循环的优化方案
先解决你问的三重循环转列表推导式的问题:
原代码的逻辑是遍历三维列表snCoords的每一层,计算每个snCoords[i][j][k]到对应centerPoints[i][j]的距离,然后把所有距离按i分组存入distances2D。用列表推导式可以直接生成整个distances2D,写法如下:
import math # 写法1:和原循环逻辑完全对应(用索引遍历) distances2D = [ [ math.dist(centerPoints[i][j], sn) for j in range(len(snCoords[i])) for sn in snCoords[i][j] ] for i in range(len(snCoords)) ] # 写法2:更易读(用zip遍历,避免索引) distances2D = [ [ math.dist(center, sn) for center, sn_group in zip(center_points_i, sn_coords_i) for sn in sn_group ] for center_points_i, sn_coords_i in zip(centerPoints, snCoords) ]
列表推导式就是把嵌套循环“扁平化”,外层对应i的循环,中间层是j和k的循环(注意顺序要和原循环一致:先j再k),最内层是距离计算逻辑。这种写法比原for循环+append的方式快一些,因为Python内部对列表推导式做了优化。
如果要进一步提升效率(尤其是数据量大的时候),用numpy向量化运算是更好的选择——纯Python循环在处理大规模数据时速度很慢,numpy的运算在C底层执行,效率能提升几十甚至上百倍。步骤如下:
import numpy as np # 把列表转换成numpy数组(假设所有坐标都是二维的,比如(x,y)) center_np = np.array(centerPoints) # 形状为 (I, J, 2) sn_np = np.array(snCoords) # 形状为 (I, J, K, 2) # 向量化计算欧氏距离:自动广播维度,一次性计算所有距离 # 先计算坐标差的平方和,再开根号 distance_matrix = np.sqrt(np.sum((sn_np - center_np[:, :, np.newaxis, :]) ** 2, axis=-1)) # 把每个i对应的所有距离 flatten 成一维列表,转成Python列表格式 distances2D = distance_matrix.reshape(distance_matrix.shape[0], -1).tolist()
简单解释:
center_np[:, :, np.newaxis, :]给center_np增加一个维度,让它和sn_np的维度匹配(变成(I,J,1,2)),这样numpy可以自动广播,对每个centerPoints[i][j]和对应的snCoords[i][j][k]做减法。axis=-1表示对最后一个维度(坐标的x、y分量)求和,得到每个点对的平方距离,再开根号就是欧氏距离。reshape把每个i对应的(J,K)形状的距离矩阵拉成一维,和原代码中distances2D[i]的结构完全一致。
内容的提问来源于stack exchange,提问作者abcd
相关产品推荐
相关产品推荐

