b2aff6009
b2aff6009

Reputation: 63

Pythonic way to calc distance between list of points

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

Answers (3)

user16912364
user16912364

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

Netwave
Netwave

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

dsm
dsm

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

Related Questions