Immutable ProximityMap implementation for TypeScript
npm install @rimbu/proximity

!License
!Types Included
!Node
!Bun
!ESM + CJS
@rimbu/proximityImmutable 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.
---
1. Why @rimbu/proximity?
2. Feature Highlights
3. Quick Start
4. Core Concepts & Types
5. Configuring Distance Functions & Contexts
6. Installation
7. FAQ
8. Ecosystem & Integration
9. Contributing
10. License
---
@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 – get uses a DistanceFunction to find the nearest key.
- Immutable operations – all updates return new maps, with structural sharing.
- Configurable metric – plug in any DistanceFunction that returns a non‑negative number.
- Familiar map semantics – insertion, removal, streaming, and builders behave like other Rimbu maps.
---
- Nearest-key lookup – get returns 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.Builder to perform many mutations before freezing.
- Context-based configuration – use ProximityMap.createContext to configure the distance function and
underlying HashMap context once and reuse it across instances.
---
``ts
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.
---
| Name | Description |
| ----------------------------- | -------------------------------------------------------------------------------------------------------- |
| ProximityMap | Immutable, type‑invariant map where lookups are resolved using a DistanceFunction over keys. |ProximityMap.NonEmpty
| | Non‑empty refinement of ProximityMap with stronger type guarantees. |ProximityMap.Context
| | Factory/context for creating proximity maps; holds the distanceFunction and backing HashMap context. |ProximityMap.Builder
| | 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
| | (one: T, another: T) => Distance – measures the distance between two values. |DistanceFunction.defaultFunction
| | Default distance function based on ===. |NearestKeyMatch
| | 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.
`ts
import { ProximityMap } from '@rimbu/proximity';
// Construction
const empty = ProximityMap.empty
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);
}
`
---
By default, the ProximityMap context uses DistanceFunction.defaultFunction, which behaves like aDistanceFunction
regular equality-based map. To unlock proximity behaviour, supply a custom :
`ts
import { ProximityMap } from '@rimbu/proximity';
import { DistanceFunction } from '@rimbu/proximity/common';
// Example: distance on numbers (absolute difference)
const numericDistance: DistanceFunction
const NumericProximityMap = ProximityMap.createContext
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.
---
`sh`
npm install @rimbu/proximityor
yarn add @rimbu/proximityor
bun add @rimbu/proximityor
deno add npm:@rimbu/proximity
@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.
---
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 andNumber.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.ProximityMap.Builder
For batch mutations, use a .
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.
---
- 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.
---
We welcome contributions! See the
Contributing guide for details.
_Made with contributors-img._
---
MIT © Rimbu contributors. See LICENSE for details.
---
Created and maintained by Arvid Nicolaas and
Gianluca Costa. Logo © Rimbu.