@rimbu/proximity
v2.0.11
Published
Immutable ProximityMap implementation for TypeScript
Maintainers
Readme
@rimbu/proximity
Immutable proximity-based maps for TypeScript & JavaScript.
@rimbu/proximity provides the ProximityMap collection: an immutable map where lookups are resolved
by closest key, according to a configurable DistanceFunction. Instead of only matching exact keys,
you can express “nearness” (numbers, vectors, coordinates, scores, etc.) and always retrieve the value
whose key is closest to the one you query.
Use it when you need nearest-neighbour lookups, tolerant matching, or when reasoning about distance between keys is more natural than exact equality.
Table of Contents
- Why
@rimbu/proximity? - Feature Highlights
- Quick Start
- Core Concepts & Types
- Configuring Distance Functions & Contexts
- Installation
- FAQ
- Ecosystem & Integration
- Contributing
- License
Why @rimbu/proximity?
Classic maps answer the question: “What value is stored for this exact key?”
Sometimes you really need: “What value is stored for the key closest to this one?”
Examples:
- Numeric thresholds – map score ranges to labels, but query by actual score.
- Timestamps – find the closest recorded event to a given time.
- Spatial / metric data – locations, distances, or any metric space.
- Fuzzy matching – use a custom distance (e.g. edit distance) instead of strict equality.
ProximityMap focuses on:
- Proximity-aware lookups –
getuses aDistanceFunctionto find the nearest key. - Immutable operations – all updates return new maps, with structural sharing.
- Configurable metric – plug in any
DistanceFunction<T>that returns a non‑negative number. - Familiar map semantics – insertion, removal, streaming, and builders behave like other Rimbu maps.
Feature Highlights
- Nearest-key lookup –
getreturns the value whose key has the smallest distance from the query key. - Configurable distance – use the default
DistanceFunction.defaultFunction(based on===), or supply your own for numbers, vectors, dates, etc. - Immutable & persistent – efficient structural sharing, ideal for functional and reactive code.
- Builders for bulk updates – use
ProximityMap.Builderto perform many mutations before freezing. - Context-based configuration – use
ProximityMap.createContextto configure the distance function and underlyingHashMapcontext once and reuse it across instances.
Quick Start
import { ProximityMap } from '@rimbu/proximity';
// Default context uses a strict equality-based distance:
// DistanceFunction.defaultFunction: 0 if a === b, +Infinity otherwise.
const map = ProximityMap.of<[number, string]>(
[10, 'low'],
[20, 'medium'],
[30, 'high']
);
// Exact match: behaves like a normal Map
console.log(map.get(20)); // 'medium'
// Nearest neighbour lookup:
// the closest stored key to 18 is 20
console.log(map.get(18)); // 'medium'Try Rimbu (including @rimbu/proximity) live in the browser using the
Rimbu Sandbox on CodeSandbox.
Core Concepts & Types
Exported Types (from @rimbu/proximity/map)
| Name | Description |
| ----------------------------- | -------------------------------------------------------------------------------------------------------- |
| ProximityMap<K, V> | Immutable, type‑invariant map where lookups are resolved using a DistanceFunction over keys. |
| ProximityMap.NonEmpty<K, V> | Non‑empty refinement of ProximityMap<K, V> with stronger type guarantees. |
| ProximityMap.Context<UK> | Factory/context for creating proximity maps; holds the distanceFunction and backing HashMap context. |
| ProximityMap.Builder<K, V> | Mutable builder for efficiently constructing or transforming a ProximityMap before freezing it. |
From @rimbu/proximity/common:
| Name | Description |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| Distance | A non‑negative number representing the distance between two values (0 = equal, Number.POSITIVE_INFINITY = no match). |
| DistanceFunction<T> | (one: T, another: T) => Distance – measures the distance between two values. |
| DistanceFunction.defaultFunction | Default distance function based on ===. |
| NearestKeyMatch<K, V> | Result object describing the closest key, its value, and the associated distance. |
| findNearestKeyMatch | Utility to find the nearest key/value pair in an iterable of entries, used internally by ProximityMap. |
See the full Proximity docs and
API reference for all operations.
Basic Operations
import { ProximityMap } from '@rimbu/proximity';
// Construction
const empty = ProximityMap.empty<number, string>();
const fromEntries = ProximityMap.of<[number, string]>(
[0, 'origin'],
[5, 'near'],
[10, 'far']
);
// Size & emptiness
empty.isEmpty; // true
fromEntries.size; // 3
// Nearest-key lookups
fromEntries.get(4); // 'near' (closest key to 4 is 5)
fromEntries.get(8); // 'far' (closest key to 8 is 10)
// Updating (returns new ProximityMap)
const updated = fromEntries.set(7, 'mid');
// Iteration / streaming (via Rimbu's stream API)
for (const [k, v] of updated) {
console.log(k, v);
}Configuring Distance Functions & Contexts
By default, the ProximityMap context uses DistanceFunction.defaultFunction, which behaves like a
regular equality-based map. To unlock proximity behaviour, supply a custom DistanceFunction:
import { ProximityMap } from '@rimbu/proximity';
import { DistanceFunction } from '@rimbu/proximity/common';
// Example: distance on numbers (absolute difference)
const numericDistance: DistanceFunction<number> = (a, b) => Math.abs(a - b);
const NumericProximityMap = ProximityMap.createContext<number>({
distanceFunction: numericDistance,
});
const numericMap = NumericProximityMap.of<[number, string]>(
[10, 'low'],
[20, 'medium'],
[40, 'high']
);
numericMap.get(22); // 'medium' (closest key is 20)
numericMap.get(35); // 'high' (closest key is 40)You can also customize the underlying HashMap context via the hashMapContext option if you need
different hashing or equality semantics.
For more advanced usage (builders, non‑empty variants, streaming, etc.), see the
ProximityMap API docs.
Installation
Node / Bun / npm / Yarn
npm install @rimbu/proximity
# or
yarn add @rimbu/proximity
# or
bun add @rimbu/proximity
# or
deno add npm:@rimbu/proximityBrowser / ESM
@rimbu/proximity ships both ESM and CJS builds. Use it with any modern bundler
(Vite, Webpack, esbuild, Bun, etc.) or directly in Node ESM projects.
FAQ
Q: How is a ProximityMap different from a regular Map?
A ProximityMap doesn’t only match exact keys – it uses a DistanceFunction to find the closest key
and returns its value, making it ideal for numeric, temporal, or spatial data.
Q: What distance function is used by default?
By default, DistanceFunction.defaultFunction is used, which returns 0 when a === b and
Number.POSITIVE_INFINITY otherwise – effectively behaving like a standard map.
Q: Is the structure mutable?
No. All updates return new ProximityMap instances; existing ones remain unchanged and can be shared safely.
For batch mutations, use a ProximityMap.Builder.
Q: Can I iterate keys or values separately?
Yes – ProximityMap implements the Rimbu RMap interfaces, so you can stream entries, keys, and values
using the standard Rimbu streaming utilities.
Ecosystem & Integration
- Part of the broader Rimbu collection ecosystem – interoperates with
@rimbu/hashed,@rimbu/collection-types, and@rimbu/stream. - Ideal for modelling nearest‑neighbour queries, thresholds, scoring systems, and fuzzy matching.
- Works seamlessly with other Rimbu collections and utilities for building rich, immutable data models.
Explore more at the Rimbu documentation and the
Proximity API docs.
Contributing
We welcome contributions! See the Contributing guide for details.
Made with contributors-img.
License
MIT © Rimbu contributors. See LICENSE for details.
Attributions
Created and maintained by Arvid Nicolaas and Gianluca Costa. Logo © Rimbu.
