Skip to content

Added Manhattan distance algorithm #7790

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 30, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions maths/manhattan_distance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
from typing import Any


def manhattan_distance(point_a: list, point_b: list) -> float:
"""
Expectts two list of numbers representing two points in the same
n-dimensional space

https://en.wikipedia.org/wiki/Taxicab_geometry

>>> manhattan_distance([1,1], [2,2])
2.0
>>> manhattan_distance([1.5,1.5], [2,2])
1.0
>>> manhattan_distance([1.5,1.5], [2.5,2])
1.5
>>> manhattan_distance([-3, -3, -3], [0, 0, 0])
9.0
>>> manhattan_distance([1,1], None)
Traceback (most recent call last):
...
ValueError: Missing an input
>>> manhattan_distance([1,1], [2, 2, 2])
Traceback (most recent call last):
...
ValueError: Both points must be in the same n-dimensional space
>>> manhattan_distance([1,"one"], [2, 2, 2])
Traceback (most recent call last):
...
TypeError: Expected a list of numbers as input, found str
>>> manhattan_distance(1, [2, 2, 2])
Traceback (most recent call last):
...
TypeError: Expected a list of numbers as input, found int
>>> manhattan_distance([1,1], "not_a_list")
Traceback (most recent call last):
...
TypeError: Expected a list of numbers as input, found str
"""

_validate_point(point_a)
_validate_point(point_b)
if len(point_a) != len(point_b):
raise ValueError("Both points must be in the same n-dimensional space")

total_distance = 0.0
for i in range(len(point_a)):
total_distance += abs(point_a[i] - point_b[i])

return total_distance


def _validate_point(point: Any) -> None:
"""
>>> _validate_point(None)
Traceback (most recent call last):
...
ValueError: Missing an input
>>> _validate_point([1,"one"])
Traceback (most recent call last):
...
TypeError: Expected a list of numbers as input, found str
>>> _validate_point(1)
Traceback (most recent call last):
...
TypeError: Expected a list of numbers as input, found int
>>> _validate_point("not_a_list")
Traceback (most recent call last):
...
TypeError: Expected a list of numbers as input, found str
"""
if point:
if isinstance(point, list):
for item in point:
if not (isinstance(item, int) or isinstance(item, float)):
raise TypeError(
f"Expected a list of numbers as input, "
f"found {type(item).__name__}"
)
else:
raise TypeError(
f"Expected a list of numbers as input, found {type(point).__name__}"
)
else:
raise ValueError("Missing an input")


def manhattan_distance_one_liner(point_a: list, point_b: list) -> float:
"""
Version with one liner

>>> manhattan_distance_one_liner([1,1], [2,2])
2.0
>>> manhattan_distance_one_liner([1.5,1.5], [2,2])
1.0
>>> manhattan_distance_one_liner([1.5,1.5], [2.5,2])
1.5
>>> manhattan_distance_one_liner([-3, -3, -3], [0, 0, 0])
9.0
>>> manhattan_distance_one_liner([1,1], None)
Traceback (most recent call last):
...
ValueError: Missing an input
>>> manhattan_distance_one_liner([1,1], [2, 2, 2])
Traceback (most recent call last):
...
ValueError: Both points must be in the same n-dimensional space
>>> manhattan_distance_one_liner([1,"one"], [2, 2, 2])
Traceback (most recent call last):
...
TypeError: Expected a list of numbers as input, found str
>>> manhattan_distance_one_liner(1, [2, 2, 2])
Traceback (most recent call last):
...
TypeError: Expected a list of numbers as input, found int
>>> manhattan_distance_one_liner([1,1], "not_a_list")
Traceback (most recent call last):
...
TypeError: Expected a list of numbers as input, found str
"""

_validate_point(point_a)
_validate_point(point_b)
if len(point_a) != len(point_b):
raise ValueError("Both points must be in the same n-dimensional space")

return float(sum(abs(x - y) for x, y in zip(point_a, point_b)))


if __name__ == "__main__":
import doctest

doctest.testmod()