Python: reduce tuple tuple

I am trying to calculate in Python the length of a path from point A to point B passing through a list of intermediate points. I know how to do this, but I want to use the reduce function of an inline function .

Why I tried so far, please note that this is completely wrong , this is what:

reduce(lambda x,y: math.sqrt((y[1]-y[0])**2+(x[1]-x[0])**2) , ((1,2),(3,4),(1,8))) 

Any idea?

Thanks.

+4
source share
8 answers

Before you reduce, you must draw a map.

 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) 

or, if you should use reduce() , although sum() better for this purpose:

 import operator total_distance = reduce(operator.add, distances) 

If you have a lot of points, you can find NumPy useful for this right away, quickly:

 import numpy total_distance = numpy.hypot(*numpy.diff(numpy.array(points), axis=0)).sum() 

Edit : use math.hypot() and add the NumPy method.

+6
source

This is not very, but it can be done :-)

 >>> 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 
+4
source

reduce() is just the wrong tool for this purpose. This can be done using reduce() , but it is a bit strange:

 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] 

prints

 7.30056307975 

The last parameter passed to the reduce() call is the starting point and the starting value for the distance.

+2
source

reduce does not work, you start with the initial value of a, which you specify or accept as the first element from your iterable. after that you pass a next_element to the function (lambda) and save the result to a, repeat until all elements are iterated.

You can do what you want with the sum and map, first calculating all the distances from one point to the next, and then summing them up:

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

edit: or using the hypot function (thanks @ralu):

 sum(map(lambda x,y: math.hypot(x[0]-y[0],x[1]-y[1]), path[:-1],path[1:])) 
+1
source

Here is the redux meta iterator that you can combine with the built-in reduce to get the result you want. This implementation avoids all buffering of the input sequence.

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

The above prints are 7.30056307975 .

The redux function can be generalized to support more than two arguments at a time in a sliding window using inspect.getargspec to count the number of arguments required by its function argument.

+1
source

This is just not the code you want to write. Cutting would not be a good solution.

I suggest an iterative option. This will be the most readable, python and supported solution.

 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 ) 
+1
source

I know that what I am going to offer is not perfect, but I think it is as close as possible to my contribution. This is an interesting problem to solve, even if it is not the most traditional shortening application.

The key problem, apparently, is tracking the distance from point to point without overwriting the points themselves - adding another “dimension” to each point gives you a field with which you can track the mileage.

 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,) # eg (3, 4, 2.828) 

Now reduce:

 reduce(func, iterable)[-1] # returns 7.3005630797457695 

Thus, the intermediate tuple of tuples (that is, after one “reduction”) becomes:

 ((3, 4, 2.8284271247461903), (1,8,0)) 
0
source

Just for fun, here is an alternative solution with a slightly different approach than the reduce(sum, map(hypot, zip(...))) approach.

 tot = ((1,2),(3,4),(1,8)) reduce(lambda (d,(x,y)),b: (d+math.hypot(xb[0],yb[1]), b), tot, (0, tot[0]))[0] 

Note that reduce actually returns a tuple (distance, last point), hence [0] at the end. I think this would be more efficient than a zip solution, but not really verified.

0
source

Source: https://habr.com/ru/post/1381739/


All Articles