From bc0bbe935942fa6c54f2e9e71f49351c85d7e956 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Sun, 5 Jan 2025 18:15:04 +0000 Subject: Add helper for merging close elements in a vector --- lib/collections.h | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'lib') diff --git a/lib/collections.h b/lib/collections.h index ea5d5dc..6f26eae 100644 --- a/lib/collections.h +++ b/lib/collections.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -224,3 +225,40 @@ strip_end(IterableCollection auto & cont) { return stripiter {cont.end()}; } + +template +void +mergeClose(std::vector & range, const Dist & dist, const Merger & merger, + decltype(dist(range.front(), range.front())) tolerance) +{ + using DistanceType = decltype(tolerance); + std::vector distances; + distances.reserve(range.size() - 1); + std::ranges::transform(range | std::views::pairwise, std::back_inserter(distances), [&dist](const auto & pair) { + return (std::apply(dist, pair)); + }); + while (distances.size() > 1) { + const auto closestPair = std::ranges::min_element(distances); + if (*closestPair > tolerance) { + return; + } + const auto offset = std::distance(distances.begin(), closestPair); + const auto idx = static_cast(offset); + if (closestPair == distances.begin()) { + // Remove second element + range.erase(range.begin() + 1); + distances.erase(distances.begin()); + } + else if (closestPair == --distances.end()) { + // Remove second from last element + range.erase(range.end() - 2); + distances.erase(distances.end() - 1); + } + else { + range[idx] = merger(range[idx], range[idx + 1]); + range.erase(range.begin() + offset + 1); + distances.erase(distances.begin() + offset); + } + distances[idx] = dist(range[idx], range[idx + 1]); + } +} -- cgit v1.2.3