[英]Python: reduce on tuple of tuples
我試圖在Python中計算從A點到B點通過中間點列表的路徑長度。 我知道怎么做,但我確實想使用reduce Built-in功能 。
為什么我到目前為止嘗試過, 請注意這是完全錯誤的 ,是這樣的:
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方法。
它不漂亮但可以做到:-)
>>> 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
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不會以這種方式工作,您從初始值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:]))
這是一個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
函數推廣為在滑動窗口中一次支持兩個以上的參數。
這不是您想要編寫的代碼。 減少不是一個好的解決方案。
我建議一個迭代的。 它將是最具可讀性,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 )
我知道我所建議的並不理想,但我認為這與我的貢獻一樣接近。 這是一個有趣的問題,即使它不是最傳統的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
這樣,元組的中間元組(即,在'減少'之后)變為:
((3, 4, 2.8284271247461903), (1,8,0))
只是為了好玩,這里是一個替代解決方案,與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
解決方案更有效但實際上沒有檢查過。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.