我正在尝试根据python的限制将递归函数转换为迭代函数。
我正在将在this answer中找到的算法从Javascript修改为Python。为了更好地解释算法,我建议您阅读链接的答案,因为它更加简洁。这样做的高级目的是沿着由经/纬度对(点)组成的“线”上找到等距点。但是,由于Python中最大的递归深度限制,我在递归move_along_path
函数中遇到了问题。阅读一些类似的问题后,我发现最好的方法是将其转换为迭代函数。我什至无法开始转换。
这是我改编的两个函数,其中move_along_path
是有时也调用move_towards
的递归函数(只有一个需要转换的函数)。
如何开始转换?转换时要考虑哪些基本步骤?
# This is the base function that calls the recursive function
def get_equidistant_markers_from_polyline_points(self, points):
points = points[1::10]
# Get markers
next_marker_at = 0
markers = []
while True:
next_point = self.iterative_move_along_path(points, next_marker_at)
if next_point is not None:
markers.append({'lat': next_point[0], 'lng': next_point[1]})
next_marker_at += 80000 # About 50 miles
else:
break
print(markers)
return markers
# This function moves from point to point along a "path" of points.
# Once the "distance" threshold has been crossed then it adds the point
# to a list of equidistant markers.
def move_along_path(self, points, distance, index=0):
if index < len(points) - 1:
# There is still at least one point further from this point
# Turn points into tuples for geopy format
# point1_tuple = (points[index]['latitude'], points[index]['longitude'])
# point2_tuple = (points[index + 1]['latitude'], points[index + 1]['longitude'])
point1_tuple = (points[index]['lat'], points[index]['lng'])
point2_tuple = (points[index + 1]['lat'], points[index + 1]['lng'])
# Use geodesic method to get distance between points in meters
distance_to_next_point = geopy.distance.geodesic(point1_tuple, point2_tuple).m
if distance <= distance_to_next_point:
# Distance_to_next_point is within this point and the next
# Return the destination point with moveTowards()
return self.move_towards(point1_tuple, point2_tuple, distance)
else:
# The destination is further from the next point
# Subtract distance_to_next_point from distance and continue recursively
return self.move_along_path(points, distance - distance_to_next_point, index + 1)
else:
# There are no further points, the distance exceeds the length of the full path.
# Return None
return None
def move_towards(point1, point2, distance):
# Convert degrees to radians
lat1 = math.radians(point1[0])
lon1 = math.radians(point1[1])
lat2 = math.radians(point2[0])
d_lon = math.radians(point2[1] - point1[1])
# Find the bearing from point1 to point2
bearing = math.atan2(math.sin(d_lon) * math.cos(lat2),
math.cos(lat1) * math.sin(lat2) -
math.sin(lat1) * math.cos(lat2) *
math.cos(d_lon))
# Earth's radius
ang_dist = distance / 6371000.0
# Calculate the destination point, given the source and bearing
lat2 = math.asin(math.sin(lat1) * math.cos(ang_dist) +
math.cos(lat1) * math.sin(ang_dist) *
math.cos(bearing))
lon2 = lon1 + math.atan2(math.sin(bearing) * math.sin(ang_dist) *
math.cos(lat1),
math.cos(ang_dist) - math.sin(lat1) *
math.sin(lat2))
if math.isnan(lat2) or math.isnan(lon2):
return None
return [math.degrees(lat2), math.degrees(lon2)]
答案 0 :(得分:0)
我对python并不是最好的选择,所以我确定您可以对其进行优化,但是一般的想法是,除了调用递归函数外,您还可以执行while循环,直到满足条件为止,然后在循环中进行修改如果您将变量作为参数传递给递归函数,则这些变量将按照您要做的事情进行处理。
def move_along_path(self, points, distance, index=0):
if index < len(points) - 1:
point1_tuple = (points[index]['lat'], points[index]['lng'])
point2_tuple = (points[index + 1]['lat'], points[index + 1]['lng'])
distance_to_next_point = geopy.distance.geodesic(point1_tuple, point2_tuple).m
while distance > distance_to_next_point:
point1_tuple = (points[index]['lat'], points[index]['lng'])
point2_tuple = (points[index + 1]['lat'], points[index + 1]['lng'])
# Use geodesic method to get distance between points in meters
distance_to_next_point = geopy.distance.geodesic(point1_tuple, point2_tuple).m
distance -= distance_to_next_point
index++
return self.move_towards(point1_tuple, point2_tuple, distance)
else
return None
答案 1 :(得分:0)
假设您发布的代码正确,我认为以下函数可以作为迭代方法来替换当前的递归函数:
def iterative_move_along_path(self, points, distance, index=0):
while index < len(points) - 1:
# There is still at least one point further from this point
# Turn points into tuples for geopy format
# point1_tuple = (points[index]['latitude'], points[index]['longitude'])
# point2_tuple = (points[index + 1]['latitude'], points[index + 1]['longitude'])
point1_tuple = (points[index]['lat'], points[index]['lng'])
point2_tuple = (points[index + 1]['lat'], points[index + 1]['lng'])
# Use geodesic method to get distance between points in meters
distance_to_next_point = geopy.distance.geodesic(point1_tuple, point2_tuple).m
if distance <= distance_to_next_point:
# Distance_to_next_point is within this point and the next
# Return the destination point with moveTowards()
return self.move_towards(point1_tuple, point2_tuple, distance)
else:
# The destination is further from the next point
# Subtract distance_to_next_point from distance and continue recursively
distance -= distance_to_next_point
index += 1
# There are no further points, the distance exceeds the length of the full path.
# Return None
return None
作为递归的一个步骤,从递归返回时,似乎与先前计算的值没有依赖性,因此,while
循环的简单正确插入以及变量的正确更新应该是正确的锻炼。