@rimbu/table
Version:
Immutable spreadsheet-like data structures containing row keys, column keys, and cell values
270 lines (186 loc) • 9.89 kB
Markdown
<p align="center">
<img src="https://github.com/rimbu-org/rimbu/raw/main/assets/rimbu_logo.svg" height="96" alt="Rimbu Logo" />
</p>
<div align="center">
[](https://www.npmjs.com/package/@rimbu/table)





</div>
# `@rimbu/table`
**Immutable, spreadsheet‑like tables for TypeScript & JavaScript.**
`@rimbu/table` provides efficient, type‑safe **Table** collections: immutable 2‑dimensional maps indexed by **row keys** and **column keys**, where each `(row, column)` pair has at most one value. It also ships concrete variants backed by hashed or sorted maps for both rows and columns.
Use it whenever you need **grid‑like data**, **2D indexing**, or want to avoid juggling nested maps manually.
---
## Table of Contents
1. [Why `@rimbu/table`?](#why-rimbu-table)
2. [Feature Highlights](#feature-highlights)
3. [Quick Start](#quick-start)
4. [Core Concepts & Types](#core-concepts--types)
5. [Working with Hash & Sorted Tables](#working-with-hash--sorted-tables)
6. [Performance Notes](#performance-notes)
7. [Installation](#installation)
8. [FAQ](#faq)
9. [Ecosystem & Integration](#ecosystem--integration)
10. [Contributing](#contributing)
11. [License](#license)
---
## Why `@rimbu/table`?
Plain maps give you **key → value** lookups, but some datasets are naturally **2‑dimensional**:
- **Spreadsheets and matrices** – cells addressed by `(row, column)` keys.
- **Time‑series grids** – `userId × day`, `metric × timeBucket`, etc.
- **Indexing external data** – look up a value by two dimensions without nested maps.
`@rimbu/table` focuses on:
- **Row/column semantics** – explicit 2D API instead of nested `Map<Map<…>>`.
- **Immutable operations** – updates return new instances with structural sharing.
- **Configurable backing maps** – choose hash or sorted maps for rows and columns.
- **Rich traversal utilities** – stream by entries, rows, or values.
If you find yourself nesting maps or objects to simulate a grid, a `Table` is usually a better fit.
---
## Feature Highlights
- **2D lookups** – efficient `(row, column) → value` access.
- **Row‑level operations** – get, filter, or remove entire rows at once.
- **Hash or sorted variants** – choose between hashed or ordered semantics for rows and columns.
- **Immutable & persistent** – structural sharing for fast copies and diffs.
- **Configurable contexts** – use `Table.createContext` or concrete table variants to control underlying map types.
- **Builder support** – mutable builders for efficient bulk construction.
---
## Quick Start
```ts
import { HashTableHashColumn } from '@rimbu/table/hash-row';
// Create a hash-based table: hashed rows, hashed columns
const table = HashTableHashColumn.of<[number, string, boolean]>(
[1, 'a', true],
[1, 'b', false],
[2, 'a', false]
);
// Look up a single cell
console.log(table.get(1, 'a')); // true
// Check presence
table.hasRowKey(2); // true
table.hasValueAt(1, 'c'); // false
// Immutable updates
const updated = table.set(2, 'b', true);
console.log(updated.get(2, 'b')); // true
```
You can also work with the generic `Table` interface via a custom context:
```ts
import { HashMap } from '@rimbu/hashed';
import { Table } from '@rimbu/table';
// Create a generic Table context using hash maps for rows and columns
const ctx = Table.createContext<number, string>({
rowContext: HashMap.defaultContext<number>(),
columnContext: HashMap.defaultContext<string>(),
});
const t = ctx.of<[number, string, boolean]>([1, 'a', true], [2, 'b', false]);
console.log(t.get(2, 'b')); // false
console.log(t.amountRows); // 2
```
Try Rimbu (including `@rimbu/table`) live in the browser using the
[Rimbu Sandbox on CodeSandbox](https://codesandbox.io/s/github/vitoke/rimbu-sandbox/tree/main?previewwindow=console&view=split&editorsize=65&moduleview=1&module=/src/index.ts).
---
## Core Concepts & Types
### Exported Types (main package)
From `@rimbu/table`:
| Name | Description |
| -------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `Table<R, C, V>` | Type‑invariant immutable table of row key type `R`, column key type `C`, and value type `V`. |
| `Table.NonEmpty<R, C, V>` | Non‑empty refinement of `Table<R, C, V>` with stronger guarantees. |
| `Table.Context<UR, UC>` | Factory/context for creating `Table` instances for upper row type `UR` and upper column type `UC`. |
| `Table.Builder<R, C, V>` | Mutable builder for efficiently constructing or mutating a `Table` before freezing it into an immutable value. |
| `VariantTable<R, C, V>` | Type‑variant view over a table; allows safe type‑widening of keys/values without mutation operations. |
| `VariantTable.NonEmpty<R, C, V>` | Non‑empty refinement of `VariantTable<R, C, V>`. |
See the full [Table docs](https://rimbu.org/docs/collections/table) and
[API reference](https://rimbu.org/api/rimbu/table) for all operations.
---
## Working with Hash & Sorted Tables
The package also exports specialized table types from sub‑packages:
- `@rimbu/table/hash-row`
- `HashTableHashColumn<R, C, V>` – **hashed rows**, **hashed columns**.
- `HashTableSortedColumn<R, C, V>` – **hashed rows**, **sorted columns**.
- `@rimbu/table/sorted-row`
- `SortedTableHashColumn<R, C, V>` – **sorted rows**, **hashed columns**.
- `SortedTableSortedColumn<R, C, V>` – **sorted rows**, **sorted columns**.
Each of these types exports:
- `*.NonEmpty<R, C, V>` – non‑empty refinements.
- `*.Context<UR, UC>` – context types.
- `*.Builder<R, C, V>` – table builders.
And each has a corresponding creators object:
```ts
import {
HashTableHashColumn,
HashTableSortedColumn,
} from '@rimbu/table/hash-row';
import {
SortedTableHashColumn,
SortedTableSortedColumn,
} from '@rimbu/table/sorted-row';
// Hash rows + hash columns
const hh = HashTableHashColumn.empty<number, string, boolean>();
// Hash rows + sorted columns
const hs = HashTableSortedColumn.of<[number, string, number]>(
[1, 'a', 1],
[1, 'b', 2]
);
// Sorted rows + hash columns
const sh = SortedTableHashColumn.from([
[1, 'a', true],
[2, 'b', false],
]);
// Sorted rows + sorted columns
const ss = SortedTableSortedColumn.builder<number, string, number>();
```
Choose the variant based on whether you need **ordering** for rows and/or columns (use sorted) or just **fast hash‑based lookup** (use hashed).
---
## Performance Notes
- Tables in Rimbu are built on **persistent data structures** – updates are typically \\(O(\log n)\\) and share most of their structure.
- Row and column operations are designed to behave similarly to their underlying map implementations (`HashMap` / `SortedMap`).
- Many bulk operations accept generic `StreamSource` inputs, letting you construct and transform tables efficiently from arrays, iterables, or streams.
For detailed performance characteristics and benchmarks, see the main Rimbu documentation at [rimbu.org](https://rimbu.org).
---
## Installation
### Node / Bun / npm / Yarn
```sh
npm install @rimbu/table
# or
yarn add @rimbu/table
# or
bun add @rimbu/table
# or
deno add npm:@rimbu/table
```
### Browser / ESM
`@rimbu/table` 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 `Table` different from a nested `Map<Map<…>>`?**
A `Table` gives you a dedicated 2D API (`get`, `set`, `getRow`, `removeRow`, etc.), row/column semantics, and consistent immutability guarantees, while still exposing row/column maps when needed.
**Q: What happens if I set a value at an existing `(row, column)`?**
The new value **replaces** the previous one and returns a new table instance; the original is unchanged.
**Q: Is the structure mutable?**
No. All updates return new table instances; existing ones remain unchanged and can be safely shared across your application.
**Q: Can I iterate rows or values separately?**
Yes. Use methods like `stream`, `streamRows`, `streamValues`, `forEach`, or convert to arrays/maps via `toArray` / `rowMap`.
---
## Ecosystem & Integration
- Part of the broader **Rimbu** collection ecosystem – interoperates with `@rimbu/hashed`,
`@rimbu/sorted`, `@rimbu/collection-types`, and `@rimbu/stream`.
- Ideal for modelling grids, cross‑product indices, availability matrices, and more.
- Works seamlessly with other Rimbu collections and utilities for building rich, immutable data models.
Explore more at the [Rimbu documentation](https://rimbu.org) and the
[Table API docs](https://rimbu.org/api/rimbu/table).
---
## Contributing
We welcome contributions! See the
[Contributing guide](https://github.com/rimbu-org/rimbu/blob/main/CONTRIBUTING.md) for details.
<img src="https://contrib.rocks/image?repo=rimbu-org/rimbu" alt="Contributors" />
_Made with [contributors-img](https://contrib.rocks)._
---
## License
MIT © Rimbu contributors. See [LICENSE](./LICENSE) for details.
---
## Attributions
Created and maintained by [Arvid Nicolaas](https://github.com/vitoke). Logo © Rimbu.