首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python减少嵌套循环

Python减少嵌套循环
EN

Stack Overflow用户
提问于 2017-05-11 16:54:34
回答 1查看 1.3K关注 0票数 2

所以我正在研究一个UVA问题,我有4个嵌套循环来迭代一个多边形列表(每个多边形包含一个点的列表,其中每个点包含一个整数x和y来表示它的坐标,也就是说,多边形是一个坐标为polygon.x和polygon.y的点)。

我试图减少程序中for循环的数量,以使其更高效,运行时更低。我的代码如下:

代码语言:javascript
复制
for i in range(len(polygons)): # iterate over all the different polygons in the test case
    for j in range(i+1, len(polygons)): # iterate over all the different polygons in the test case but starting from the second, in order to make comparations between polygons i and j
        for a in range(len(polygons[i])):
            if (isInside(polygons[i][a].x, polygons[i][a].y, polygons[j])):
                union(i,j)
        for a in range(len(polygons[j])):
            if (isInside(polygons[j][a].x, polygons[j][a].y, polygons[i])):
                union(i,j)
        f = 1
        for a in range(len(polygons[i])): # iterate over all the different points in the polygon i
            for b in range(len(polygons[j])): # iterate over all the different points in the polygon j
                if (f!=0):
                    if(doIntersect(polygons[i][a], polygons[i][(a+1)%len(polygons[i])],polygons[j][b], polygons[j][(b+1)%len(polygons[j])])): # check if every single pair of line segments, each one made up of two points, intersect with each other
                        union(i,j) # the two line segments intersect so we join them by using union
                        f = 0

我试图通过使用itertools.product来提高效率,如下所示:

代码语言:javascript
复制
def solve():
global polygons, p

ranges = [range(len(polygons)), range(1,len(polygons))]

for i, j in product(*ranges):
    for a in range(len(polygons[i])):
        if (isInside(polygons[i][a].x, polygons[i][a].y, polygons[j])):
            union(i,j)
    for a in range(len(polygons[j])):
        if (isInside(polygons[j][a].x, polygons[j][a].y, polygons[i])):
            union(i,j)
    f = 1
    ranges2 = [range(len(polygons[i])), range(len(polygons[j]))]
    for a,b in product(*ranges2):
        if (f!=0):
            if(doIntersect(polygons[i][a], polygons[i][(a+1)%len(polygons[i])],polygons[j][b], polygons[j][(b+1)%len(polygons[j])])): # check if every single pair of line segments, each one made up of two points, intersect with each other
                union(i,j) # the two line segments intersect so we join them by using union
                f = 0

无论如何,在这两种情况下,我的代码都具有相同的运行时,有没有办法减少我的算法中嵌套循环的数量?

谢谢您的帮助,非常感谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-05-11 17:08:58

您的两个外部循环正在创建列表的组合;为此使用 iterator。您最内部的双循环生产笛卡尔产品,所以使用 iterator

不要用range(), just loop directly over the polygon lists; use枚举()`生成索引来添加索引,而不是让索引反过来工作。

要对部分进行配对,可以使用来自 recipe菜谱部分的itertools;这将使您可以使用所有片段。若要再次循环到起点(将最后的坐标与第一个坐标配对),只需将第一个元素的列表追加到末尾即可。

一旦您摆脱了嵌套循环,就可以使用break结束它们,而不是使用标志变量。

代码语言:javascript
复制
from itertools import combinations, product

def pairwise(iterable):
    "s -> (s0,s1), (s1,s2), (s2, s3), ..."
    a, b = tee(iterable)
    next(b, None)
    return zip(a, b)

for (i, a_poly), (j, b_poly) in combinations(enumerate(polygons), 2):
    for a in a_poly:
        if isInside(a.x, a.y, b_poly):
            union(i, j)
    for b in b_poly:
        if isInside(b.x, b.y, a_poly):
            union(j, i)

    # attach the first element at the end so you go 'round'
    a_segments = pairwise(a_poly + a_poly[:1])
    b_segments = pairwise(b_poly + b_poly[:1])
    for a_seg, b_seg in product(a_segments, b_segments):
        if doIntersect(*a_seg, *b_seg):
            union(i,j)
            break

事实上,一旦你确定某件事是一个联盟,你就不需要继续其他的测试了。您可以使用 function提前停止测试isInside()doIntersect函数:

代码语言:javascript
复制
for (i, a_poly), (j, b_poly) in combinations(enumerate(polygons), 2):
    if any(isInside(a.x, a.y, b_poly) for a in a_poly):
        union(i, j)
        break  # union found, no need to look further

    for any(isInside(b.x, b.y, a_poly) for b in b_poly):
        union(i, j)
        break  # union found, no need to look further

    # attach the first element at the end so you go 'round'
    a_segments = pairwise(a_poly + a_poly[:1])
    b_segments = pairwise(b_poly + b_poly[:1])
    if any(doIntersect(*a_seg, *b_seg) 
           for a_seg, b_seg in product(a_segments, b_segments)):
        union(i,j)

这不仅是现在更多的可读性,它也应该更有效率!

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43921489

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档