Reputation: 63
I have a list of unorered points (2D) and I want to calculate the sum of distances between them. As my background is a c++ dev I would do it like this:
import math
class Point:
def __init__(self, x,y):
self.x = x
self.y = y
def distance(P1, P2):
return math.sqrt((P2.x-P1.x)**2 + (P2.y-P1.y)**2)
points = [Point(rand(1), rand(1)) for i in range(10)]
#this part should be in a nicer way
pathLen = 0
for i in range(1,10):
pathLen += distance(points[i-1], points[i])
Is there a more pythonic way to replace the for loop? e.g with reduce or something like that?
best regards!
Upvotes: 4
Views: 438
Reputation:
I ran into a similar problem and pieced together a numpy solution which I think works nicely.
Namely, if you cast your list of points as a numpy array you can then do the following:
pts = np.asarray(points)
dist = np.sqrt(np.sum((pts[np.newaxis, :, :]-pts[:, np.newaxis, :])**2, axis=2))
dist results in a nxn numpy symmetric array where the distance between each point to every other point is given above or below the diagonal. The diagonal is each point's distance to itself so just 0s.
You can then use:
path_leng = np.sum(dist[np.triu_indices(pts.shape[0], 1)].tolist())
to collect the top half of the numpy array and sum them to get the pathlength.
Upvotes: 0
Reputation: 42786
You can use a generator expresion with sum
, zip
and itertools islice
to avoid duplicating data:
from itertools import islice
paathLen = sum(distance(x, y) for x, y in zip(points, islice(points, 1, None)))
Here you have the live example
Upvotes: 2
Reputation: 2253
A few fixes, as a C++ approach is probably not the best here:
import math
# you need this import here, python has no rand in the main namespace
from random import random
class Point:
def __init__(self, x,y):
self.x = x
self.y = y
# there's usually no need to encapsulate variables in Python
def distance(P1, P2):
# your distance formula was wrong
# you were adding positions on each axis instead of subtracting them
return math.sqrt((P1.x-P2.x)**2 + (P1.y-P2.y)**2)
points = [Point(random(), random()) for i in range(10)]
# use a sum over a list comprehension:
pathLen = sum([distance(points[i-1], points[i]) for i in range(10)])
@Robin Zigmond's zip
approach is also a neat way to achieve it, though it wasn't immediately obvious to me that it could be used here.
Upvotes: 1