From 37edeb896d202c1ce48bcaffdd40bc0cf5f7e5fe Mon Sep 17 00:00:00 2001
From: josidd <joseph.siddons@noc.ac.uk>
Date: Tue, 24 Sep 2024 15:31:18 +0100
Subject: [PATCH] feat: add find_nearest function

---
 GeoSpatialTools/neighbours.py | 44 +++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)
 create mode 100644 GeoSpatialTools/neighbours.py

diff --git a/GeoSpatialTools/neighbours.py b/GeoSpatialTools/neighbours.py
new file mode 100644
index 0000000..d13b637
--- /dev/null
+++ b/GeoSpatialTools/neighbours.py
@@ -0,0 +1,44 @@
+from numpy import argmin
+from bisect import bisect
+from typing import TypeVar
+from datetime import date, datetime
+
+
+Numeric = TypeVar("Numeric", int, float, datetime, date)
+
+
+def _find_nearest(vals: list[Numeric], test: Numeric) -> int:
+    i = bisect(vals, test)  # Position that test would be inserted
+
+    # Handle edges
+    if i == 0 and test <= vals[0]:
+        return 0
+    elif i == len(vals) and test >= vals[-1]:
+        return len(vals) - 1
+
+    test_idx = [i - 1, i]
+    return test_idx[argmin([abs(test - vals[j]) for j in test_idx])]
+
+
+def find_nearest(vals: list[Numeric], test: list[Numeric]) -> list[int]:
+    """
+    Find the nearest value in a list of values for each test value.
+
+    Uses bisection for speediness!
+
+    Arguments
+    =========
+    vals : list[Numeric]
+        List of values - this is the pool of values for which we are looking
+        for a nearest match. This list MUST be sorted. Sortedness is not
+        checked, nor is the list sorted. An error will be raised if the list
+        is not sorted.
+    test : list[Numeric]
+        List of query values
+
+    Returns
+    =======
+    A list containing the index of the nearest neighbour in vals for each value
+    in test.
+    """
+    return [_find_nearest(vals, t) for t in test]
-- 
GitLab