我想在Python中计算从点A到点B经过中间点列表的路径的长度。 我知道如何去做,但我确实想使用减少内置功能。Python:减少元组的元组
为什么我试过到目前为止,请注意,这是完全错误,是这样的:
reduce(lambda x,y: math.sqrt((y[1]-y[0])**2+(x[1]-x[0])**2) , ((1,2),(3,4),(1,8)))
任何想法?
谢谢。
我想在Python中计算从点A到点B经过中间点列表的路径的长度。 我知道如何去做,但我确实想使用减少内置功能。Python:减少元组的元组
为什么我试过到目前为止,请注意,这是完全错误,是这样的:
reduce(lambda x,y: math.sqrt((y[1]-y[0])**2+(x[1]-x[0])**2) , ((1,2),(3,4),(1,8)))
任何想法?
谢谢。
在缩小之前,您应该映射。
points = [(1, 2), (3, 4), (1, 8)]
distances = (math.hypot(b[0]-a[0], b[1]-a[1])
for a, b in zip(points, points[1:]))
total_distance = sum(distances)
,或者,如果你必须使用reduce()
,虽然sum()
是一种更合理的:
import operator
total_distance = reduce(operator.add, distances)
如果你有一分不少,你可能会发现NumPy的所有在做这个有帮助一次,连忙道:
import numpy
total_distance = numpy.hypot(*numpy.diff(numpy.array(points), axis=0)).sum()
编辑:使用math.hypot()
并添加NumPy方法。
在数学中有函数hypot –
+1 @raiu,我已经编辑过使用'math.hypot()'。 –
这个解决方案缓存输入,所以对于更长的序列来说这将是昂贵的,除非'zip'表达式被重构了一点。 – wberry
reduce不起作用,你从一个初始值a开始,这个初始值是你指定的或者是你的迭代中的第一个元素。之后,将一个next_element传递给函数(lambda),并将结果存储在a中,直到所有元素都被迭代为止。
你可以做你想做的额头和地图通过首先计算从一个点都距离下一个,然后总结他们什么:
path = [(1,2),(3,4),(1,8)]
sum(map(lambda x,y: math.sqrt((x[0]-y[0])**2+(x[1]-y[1])**2), path[:-1],path[1:]))
编辑:或与hypot
功能(THX @ralu):
sum(map(lambda x,y: math.hypot(x[0]-y[0],x[1]-y[1]), path[:-1],path[1:]))
尽管命名约定和问题中的代码不正确,你的'x'实际上是坐标第一点,你的'y'是下一点的坐标。所以这不会返回正确的距离。 –
@迈克尔霍夫曼:的确,更正 – KillianDS
reduce()
仅仅是为此目的的错误工具。这是可能与reduce()
做到这一点,但它是一个有点怪异:
def distance((x, d), y):
return y, d + math.hypot(y[0] - x[0], y[1] - x[1])
print reduce(distance, [(3,4),(1,8)], ((1, 2), 0.0))[1]
打印
7.30056307975
传递给reduce()
调用的最后一个参数是出发点和初始值距离。
这是不漂亮,但它可以做到:-)
>>> tot = ((1,2),(3,4),(1,8))
>>> reduce(lambda d,((x0,y0),(x1,y1)): d + ((x1-x0)**2+(y1-y0)**2)**0.5, zip(tot[1:], tot[0:]), 0.0)
7.3005630797457695
这里是一个redux
元迭代器可与内置reduce
结合,以得到你想要的结果。该实现避免了输入序列的所有缓冲。
def redux(f):
def execute(iterable):
iterable = iter(iterable)
try:
state = iterable.next()
except StopIteration:
raise ValueError, 'empty sequences not supported'
while True:
newstate = iterable.next()
yield f(state, newstate)
state = newstate
return execute
f = redux(lambda x, y: math.sqrt((y[0] - x[0])**2 + (y[1] - x[1])**2))
print reduce(operator.add, f(((1,2),(3,4),(1,8))))
上述印刷品7.30056307975
。
通过使用inspect.getargspec
来计算其函数参数所需的参数数量,redux
函数可以推广到在滑动窗口中一次支持两个以上的参数。
这只是你想写的代码而已。 Reduce不是一个好的解决方案。
我建议迭代一个。 这将是最可读,pythonic和可维护的解决方案。
import math
path = [(1,2),(3,4),(1,8)]
def calc_dist(waypoints):
dist = 0.0
for i in range(len(waypoints) - 1):
a = waypoints[i]
b = waypoints[i+1]
dist += math.hypot(a[0]-b[0], b[1]-a[1])
return dist
print calc_dist(path)
我知道我即将提出的建议并不理想,但我认为这是尽可能接近我的贡献。这是一个有趣的问题,即使它不是最传统的减少应用程序。
关键问题似乎是跟踪点到点之间的距离而不覆盖点本身 - 为每个点添加另一个“尺寸”会为您提供一个可跟踪跑步距离的字段。
iterable = ((1,2,0), (3,4,0), (1,8,0))
# originally ((1,2), (3,4), (1,8))
from math import sqrt
def func(tup1, tup2):
'''function to pass to reduce'''
# extract coordinates
x0 = tup1[0]
x1 = tup2[0]
y0 = tup1[1]
y1 = tup2[1]
dist = tup1[2] # retrieve running total for distance
dx = x1 - x0 # find change in x
dy = y1 - y0 # find change in y
# add new distance to running total
dist += sqrt(dx**2 + dy**2)
# return 2nd point with the updated distance
return tup2[:-1] + (dist,) # e.g. (3, 4, 2.828)
现在减少:
reduce(func, iterable)[-1]
# returns 7.3005630797457695
这样,元组的中间元组(即 '减少' 一后)变为:
((3, 4, 2.8284271247461903), (1,8,0))
这基本上实现了两步缩小,使用每个元组中的第三个元素作为第一步的结果。 – wberry
只是为了好玩,这里是一个采用与reduce(sum, map(hypot, zip(...)))
方法稍有不同的方法。
tot = ((1,2),(3,4),(1,8))
reduce(lambda (d,(x,y)),b: (d+math.hypot(x-b[0],y-b[1]), b), tot, (0, tot[0]))[0]
注意,reduce
实际返回的元组(距离,最后点),因此[0]
末。我认为这将比zip
解决方案更有效,但实际上没有检查。
我不认为你可以使用'reduce'来做到这一点,或者至少它不是最佳的方式imo。从理论上讲,'reduce'会给你迄今为止计算出来的距离以及一个点作为参数,但是你需要两点来计算距离。也许有一种奇特的方式来做到这一点,但为什么不只是遍历列表? –
简单的加速技巧是对广场进行操作,最后做一个sqrt。 – qba
@qba:你在哪里得到了总和的sqrt等于sqrt总和的想法?例如:'sqrt(2)+ sqrt(2)!= sqrt(2 + 2)' – KillianDS