因此,我正在研究UVA问题,并且我有4个嵌套循环来遍历多边形列表(每个多边形都包含一个点列表,其中每个点都包含一个整数x和y来表示其坐标,即,polygon
[0]是一个点,其坐标为面[0] .x和面[0] .y)。
我试图减少程序中for循环的数量,以使其更高效并降低运行时间。我的代码如下:
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使其变得更加高效,如下所示:
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
无论如何,我的代码在两种情况下都具有相同的运行时,是否有办法减少算法的嵌套循环数?
在此先感谢您提供的任何帮助,非常感谢
您的两个外部循环正在创建列表的 组合
。为这些使用itertools.combinations()
迭代器。您最里面的双循环会产生
笛卡尔积
,因此请使用itertools.product()
迭代器。
不要使用range(), just loop directly over the polygon lists; use
enumerate()来生成索引以添加索引,而不要使索引相反。
到配对部分,该pairwise()
配方从itertools
食谱部;
这样您就可以使用所有细分。要再次从头开始绕圈(将最后一个坐标与第一个坐标配对),只需将列表的第一个元素附加到末尾即可。
一旦摆脱了嵌套循环,就可以使用break
结束循环而不是使用标志变量。
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
实际上,一旦确定某个东西是一个并集,就不必继续进行其余的测试。您可以使用any()
功能停止测试isInside()
和doIntersect
早期的功能:
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)
这不仅现在可读性强,而且还应该更有效!
Python 不仅支持 if 语句相互嵌套,while 和 for 循环结构也支持嵌套。所谓嵌套(Nest),就是一条语句里面还有另一条语句,例如 for 里面还有 for,while 里面还有 while,甚至 while 中有 for 或者 for 中有 while 也都是允许的。 当 2 个(甚至多个)循环结构相互嵌套时,位于外层的循环结构常简称为 外层循环或 外循环,位于内层的循环结构常简
问题内容: 我经常发现自己正在这样做: 在Python中有更简洁的方法吗?我在想一些类似的东西 问题答案: 您可以使用itertools.product:
问题内容: 在寻找和理解pythonic方法以优化嵌套的for循环中的以下数组操作时,我将不胜感激: 其中(182、218、200)和(3)都是类型;并且是 问题答案: 方法1 这是向量化方法- 可能的改进:我们可以通过模块加快最后一步的速度- 方法#2 我们还可以逐步构建与形状参数相对应的三个范围,并在运行中对三个元素进行减法运算,而无需像之前使用那样实际创建网格。通过出于效率目的使用会受益。实
这里是Uni learning Python编程入门课程的初学者。直到我明白了大部分,现在我很困惑。 有人能解释为什么这会产生它输出的模式吗? 外循环触发器和() 然后内部循环触发器和() 然后它不会打印(6),因为
这里是一个以圆圈为单位的交叉网格,当前为5x5。我试图得到一行5,下面是一行4,然后是3,然后是2等等。我试着改变for循环和值,但什么都不起作用。我需要使用行和列吗? 谢谢!