首页 > 解决方案 > 通过避免嵌套 for-for-if 循环中不必要的重复计算来加速脚本

问题描述

假设有大约 10**2 个已知位置和半径的圆。此外,假设已知位置有 ~10**3 个点。分布是完全随机的,我们知道如果我们探测每个圆,原则上它可以有超过 1 个点。

以下一段 python 代码旨在先循环循环,然后循环循环。它的编写方式是,对于每个圆圈,如果仅旨在跟踪至少有 1 个点的圆圈,则内部循环将重复计算无关的线。

例如,如果一个圆圈恰好有 100 个点,那么最里面的循环将运行 100 次。但是,我需要通过操作代码来避免这种情况,以便在圆内找到一个点的那一刻,循环停止检查该圆的其余点。这样,我将极大地提高代码的速度。但是,我不完全确定如何做到这一点。

# position_data and radius_data are the properties of the circles mentioned above
for circle_position, circle_radius in zip(position_data, radius_data): 

    #(x, y) are the coordinates of the points mentioned above
    for x, y in zip(vals1, vals2):   

        if (condition1 and condition2 and condition3):
            # do some stuff  (these are the stuff that I want to avoid due to repetition)

标签: pythonpython-3.xperformancefor-loopif-statement

解决方案


你看过break语句吗?请参阅Python 中断并继续

在您的条件语句中,检查是否在圆内找到一个点并在为真时中断,代码如下:

# position_data and radius_data are the properties of the circles mentioned above
for circle_position, circle_radius in zip(position_data, radius_data): 

    #(x, y) are the coordinates of the points mentioned above
    for x, y in zip(vals1, vals2):   

        # Condition to check if a point was found within a circle
        if point_in_circle(circle_position, circle_radius, x, y):
            break

对于这个条件语句,我建议将 point_in_circle 检查拉到一个单独的函数中,以提高可读性和可重用性:

def point_in_circle(cx, cy, cr, px, py):
    d = math.sqrt(
        (px - cx) ** 2 + (py - cy) ** 2
    )

    if d < cr:
        return True

这里,cx、cy 和 cr 分别是圆的 x 位置、y 位置和半径。

px, py 是该点的 x 和 y 位置。


为了帮助回答您的后续问题,我粘贴了下面的代码,少了一些评论:

# NEW
pointsWithinCircles = 0
totalPoints = len(vals1)

def point_in_circle(position_data, radius_data, x, y):
    in_circle = False
    # Logic

    return in_circle

for circle_position, circle_radius in zip(position_data, radius_data):

    for x, y in zip(vals1, vals2):

        if point_in_circle(circle_position, circle_radius, x, y):

            # NEW - Increment counter
            pointsWithinCircles += 1
            break

#NEW
pointsOutsideCircles = totalPoints - pointsWithinCircles

您可以创建一个计数器来跟踪圆圈内包含多少点。然后,从您拥有的总点数中减去pointsWithinCircles,这就是您的 vals1(或 vals2)列表的长度。


推荐阅读