@thi.ng/associative
Version:
ES Map/Set-compatible implementations with customizable equality semantics & supporting operations
272 lines (204 loc) • 10.2 kB
Markdown
<!-- This file is generated - DO NOT EDIT! -->
<!-- Please see: https://github.com/thi-ng/umbrella/blob/develop/CONTRIBUTING.md#changes-to-readme-files -->
# 
[](https://www.npmjs.com/package/@thi.ng/associative)

[](https://mastodon.thi.ng/@toxi)
> [!NOTE]
> This is one of 210 standalone projects, maintained as part
> of the [.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo
> and anti-framework.
>
> 🚀 Please help me to work full-time on these projects by [sponsoring me on
> GitHub](https://github.com/sponsors/postspectacular). Thank you! ❤️
- [About](#about)
- [Why?](#why)
- [Comparison with ES6 native types](#comparison-with-es6-native-types)
- [Status](#status)
- [Installation](#installation)
- [Dependencies](#dependencies)
- [Usage examples](#usage-examples)
- [API](#api)
- [IEquivSet](#iequivset)
- [ArraySet](#arrayset)
- [LLSet](#llset)
- [EquivMap](#equivmap)
- [HashMap](#hashmap)
- [Authors](#authors)
- [License](#license)
## About
ES Map/Set-compatible implementations with customizable equality semantics & supporting operations.
> [!IMPORTANT]
> In July 2024 this package was restructured and split-up to extract some
> features into smaller more focused packages:
>
> - [.ng/bidir-index](https://thi.ng/bidir-index)
> - [.ng/object-utils](https://thi.ng/object-utils)
> - [.ng/sorted-map](https://thi.ng/sorted-map)
> - [.ng/sparse-set](https://thi.ng/sparse-set)
> - [.ng/trie](https://thi.ng/trie)
- Array based `ArraySet`, Linked List based `LLSet` and customizable `EquivMap`
& `HashMap` implementing the full ES6 Map/Set APIs and additional features:
- `ICopy`, `IEmpty` & `IEquiv` implementations
- `ICompare` implementation for sorted types
- multiple value additions / updates / deletions via `into()`, `dissoc()`
(maps) and `disj()` (sets)
- configurable key equality & comparison (incl. default implementations)
- getters w/ optional "not-found" default value
- Polymorphic set operations (union, intersection, difference) - works with both
native and custom Sets and retains their types
- Natural & selective
[joins](https://en.wikipedia.org/wiki/Relational_algebra#Joins_and_join-like_operators)
(incl. key renaming, ported from Clojure)
Please see these packages for some example use cases:
- [.ng/cache](https://github.com/thi-ng/umbrella/tree/develop/packages/cache)
- [.ng/dgraph](https://github.com/thi-ng/umbrella/tree/develop/packages/dgraph)
- [.ng/ecs](https://github.com/thi-ng/umbrella/tree/develop/packages/ecs)
- [.ng/rstream-query](https://github.com/thi-ng/umbrella/tree/develop/packages/rstream-query)
### Why?
The native ES6 implementations use **object reference** identity to determine
key containment, but often it's **more practical and useful to use equivalent
value semantics** for this purpose, especially when keys are structured data
(arrays / objects).
**Note**: It's the user's responsibility to ensure the inserted keys are kept
immutable (even if technically they're not).
### Comparison with ES6 native types
```ts
// first two objects w/ equal values
const a = [1, 2];
const b = [1, 2];
```
Using native implementations
```ts
const set = new Set();
set.add(a);
set.has(b);
// false
const map = new Map();
map.set(a, "foo");
map.get(b);
// undefined
```
Using custom implementations:
```ts
import { defArraySet } from "@thi.ng/associative";
const set = defArraySet();
set.add(a);
set.add({a: 1});
// ArraySet { [ 1, 2 ], { a: 1 } }
set.has(b);
// true
set.has({a: 1});
// true
```
```ts
import { defLLSet } from "@thi.ng/associative";
const set = defLLSet();
set.add(a);
set.add({a: 1});
// LLSet { [ 1, 2 ], { a: 1 } }
set.has(b);
// true
set.has({a: 1});
// true
```
```ts
import { defEquivMap, ArraySet } from "@thi.ng/associative";
// by default EquivMap uses ArraySet for its canonical keys
// const map = defEquivMap();
// with custom implementation
const map = defEquivMap(null, { keys: ArraySet });
map.set(a, "foo");
// EquivMap { [ 1, 2 ] => 'foo' }
map.get(b);
// "foo"
```
```ts
import { defHashMap } from "@thi.ng/associative";
import { hash } from "@thi.ng/vectors"
// Hash map w/ user supplied hash code function
// (here using `hash` function for arrays)
const map = defHashMap([], { hash })
map.set([1, 2], "a");
map.set([3, 4, 5], "b");
map.set([1, 2], "c");
// HashMap { [ 1, 2 ] => 'c', [ 3, 4, 5 ] => 'b' }
```
## Status
**STABLE** - used in production
[Search or submit any issues for this package](https://github.com/thi-ng/umbrella/issues?q=%5Bassociative%5D+in%3Atitle)
## Installation
```bash
yarn add .ng/associative
```
ESM import:
```ts
import * as assoc from "@thi.ng/associative";
```
Browser ESM import:
```html
<script type="module" src="https://esm.run/@thi.ng/associative"></script>
```
[JSDelivr documentation](https://www.jsdelivr.com/)
For Node.js REPL:
```js
const assoc = await import("@thi.ng/associative");
```
Package sizes (brotli'd, pre-treeshake): ESM: 3.14 KB
## Dependencies
- [.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
- [.ng/arrays](https://github.com/thi-ng/umbrella/tree/develop/packages/arrays)
- [.ng/binary](https://github.com/thi-ng/umbrella/tree/develop/packages/binary)
- [.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
- [.ng/dcons](https://github.com/thi-ng/umbrella/tree/develop/packages/dcons)
- [.ng/equiv](https://github.com/thi-ng/umbrella/tree/develop/packages/equiv)
- [.ng/object-utils](https://github.com/thi-ng/umbrella/tree/develop/packages/object-utils)
- [.ng/transducers](https://github.com/thi-ng/umbrella/tree/develop/packages/transducers)
Note: .ng/api is in _most_ cases a type-only import (not used at runtime)
## Usage examples
Four projects in this repo's
[/examples](https://github.com/thi-ng/umbrella/tree/develop/examples)
directory are using this package:
| Screenshot | Description | Live demo | Source |
|:------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------|:-------------------------------------------------------------|:------------------------------------------------------------------------------------------|
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/commit-heatmap.png" width="240"/> | Heatmap visualization of this mono-repo's commits | | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/commit-heatmap) |
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/geom-webgl-attrib-pool.jpg" width="240"/> | Augmenting thi.ng/geom shapes for WebGL, using instancing & attribute buffers | [Demo](https://demo.thi.ng/umbrella/geom-webgl-attrib-pool/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/geom-webgl-attrib-pool) |
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/rdom-key-sequences.jpg" width="240"/> | rstream & transducer-based FSM for converting key event sequences into high-level commands | [Demo](https://demo.thi.ng/umbrella/rdom-key-sequences/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/rdom-key-sequences) |
| <img src="https://raw.githubusercontent.com/thi-ng/umbrella/develop/assets/examples/related-images.jpg" width="240"/> | Responsive image gallery with tag-based Jaccard similarity ranking | [Demo](https://demo.thi.ng/umbrella/related-images/) | [Source](https://github.com/thi-ng/umbrella/tree/develop/examples/related-images) |
## API
[Generated API docs](https://docs.thi.ng/umbrella/associative/)
### IEquivSet
All `Set` implementations in this package implement the
[`IEquivSet`](https://docs.thi.ng/umbrella/associative/interfaces/IEquivSet.html)
interface, an extension of the native ES6 Set API.
### ArraySet
Simple array based `Set` implementation which by default uses
[`.ng/equiv`](https://github.com/thi-ng/umbrella/tree/develop/packages/equiv)
for value equivalence checking.
### LLSet
Similar to `ArraySet`, but uses
[.ng/dcons](https://github.com/thi-ng/umbrella/tree/develop/packages/dcons) linked list
as backing storage for values.
### EquivMap
This `Map` implementation uses a native ES6 `Map` as backing storage for
its key-value pairs and an additional `IEquivSet` implementation for
canonical keys. By default uses `ArraySet` for this purpose.
### HashMap
Map implementation w/ standard ES6 Map API, supporting any key type via
hash codes computed via user supplied hash function. Uses [Open
Addressing](https://en.wikipedia.org/wiki/Open_addressing) / Linear
Probing to resolve key collisions. Customizable via `HashMapOpts`
constructor argument. Hash function MUST be given.
## Authors
- [Karsten Schmidt](https://thi.ng)
If this project contributes to an academic publication, please cite it as:
```bibtex
{thing-associative,
title = "@thi.ng/associative",
author = "Karsten Schmidt",
note = "https://thi.ng/associative",
year = 2017
}
```
## License
© 2017 - 2025 Karsten Schmidt // Apache License 2.0