Python:减少元组中的元组

Python:减少元组中的元组,python,lambda,reduce,euclidean-distance,Python,Lambda,Reduce,Euclidean Distance,我试图用Python计算从点a到点B的路径的长度,该路径通过一系列中间点我知道怎么做,但我确实想使用reduce内置函数 为什么我到目前为止一直尝试,请注意,它完全错了,,是这样的: reduce(lambda x,y: math.sqrt((y[1]-y[0])**2+(x[1]-x[0])**2) , ((1,2),(3,4),(1,8))) 有什么想法吗 谢谢。reduce不是这样工作的,您从一个初始值a开始,该值由您指定或作为iterable中的第一个元素。然后,将一个,next_元素

我试图用Python计算从点a到点B的路径的长度,该路径通过一系列中间点我知道怎么做,但我确实想使用reduce内置函数

为什么我到目前为止一直尝试,请注意,它完全错了,,是这样的:

reduce(lambda x,y: math.sqrt((y[1]-y[0])**2+(x[1]-x[0])**2) , ((1,2),(3,4),(1,8)))
有什么想法吗


谢谢。

reduce不是这样工作的,您从一个初始值a开始,该值由您指定或作为iterable中的第一个元素。然后,将一个,next_元素传递给提供的函数(lambda),并将结果存储在,repeat中,直到所有元素都被迭代

通过先计算从一个点到下一个点的所有距离,然后对它们求和,您可以使用“求和”和“映射”来执行所需操作:

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):

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()
调用的最后一个参数是距离的起点和初始值。

在进行reduce()之前,应该进行映射

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)
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()
,尽管
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方法。

这并不漂亮,但可以做到:-)


这里有一个
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
函数推广为在滑动窗口中一次支持两个以上的参数。

这不是您想要编写的代码类型。 减少并不是一个好的解决方案

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 )
我建议迭代一次。 它将是最具可读性、最具实用性和可维护性的解决方案

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 )

我知道我将要提出的建议并不理想,但我认为这是我所能得到的最接近我的贡献。这是一个需要解决的有趣问题,即使它不是reduce最传统的应用程序

关键问题似乎是在不覆盖点本身的情况下跟踪点与点之间的距离-为每个点添加另一个“维度”会为您提供一个可以跟踪跑步距离的字段

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
这样,元组的中间元组(即,在一次“缩减”之后)变为:


为了好玩,这里有一个替代解决方案,其方法与
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
可以做到这一点,或者至少在我看来这不是最佳的方法。理论上,
reduce
将给出到目前为止的计算距离和一个点作为参数,但是你需要两个点来计算距离。也许有一种奇特的方法可以做到这一点,但为什么不只是在列表上迭代呢?简单的加速技巧是对正方形进行运算,最后是一个dosqrt。@qba:你从哪里知道一个和的sqrt等于sqrt的和?e、 g.:
sqrt(2)+sqrt(2)=sqrt(2+2)
谢谢大家的回答。尽管命名惯例和问题中的错误代码,您的
x
实际上是第一个点的坐标,您的
y
是下一个点的坐标。因此,这将无法返回正确的距离。Math中有函数hypot。此解决方案缓冲输入,因此对于较长的序列,它将非常昂贵,除非对
zip
表达式进行一点重构。如果您需要一些高效的方法,那么NumPy解决方案可能是最好的。如果您必须只使用标准库,那么@Raymond Hettinger的下面介绍了如何使用
itertools.tee()
itertools.izip()
。为了避免缓冲更长的序列,
zip
表达式需要一些重构。但是聪明的黑客值得称赞+1如果涉及序列长度,则始终可以替换itertools.izip。感谢upvote:-)我指的是使用切片实现的移位,即使使用
izip
也会使用原始序列的两倍内存成本。使用itertools.tee()进行拆分,使用next()消耗其中一个的第一个值(在itertools配方中有一个例子):
t1,t2=tee(tot);其次(t2,无);it=izip(t1,t2);从我这里减少(λd,((x0,y0),(x1,y1)):d+((x1-x0)**2+(y1-y0)**2)**0.5,it,0)
+1。你的答案正是OP要求的。也许人们正在对reduce本身而不是你的答案进行向下投票。这实际上实现了两步reduce,使用每个元组中的第三个元素作为第一步的结果。
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]