npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@rimbu/multiset

v2.1.6

Published

An immutable Set where each element can occur multiple times

Downloads

15,955

Readme

npm version License Types Included Node Bun ESM + CJS

@rimbu/multiset

Fast, immutable multisets (bags) for TypeScript & JavaScript.

@rimbu/multiset provides efficient, type‑safe MultiSet implementations: set‑like collections where each distinct element can appear multiple times, and the structure tracks how often each element occurs. This is ideal when element frequency matters, such as counters, histograms, weighted collections, or multi‑valued states.

Use it whenever you need to model “how many times” something appears rather than just whether it exists, without giving up immutability or strong typing.


Table of Contents

  1. Why @rimbu/multiset?
  2. Feature Highlights
  3. Quick Start
  4. Core Concepts & Types
  5. Working with Hash & Sorted MultiSets
  6. Performance Notes
  7. Installation
  8. FAQ
  9. Ecosystem & Integration
  10. Contributing
  11. License
  12. Attributions

Why @rimbu/multiset?

Plain sets and maps only tell you whether a value is present, not how many times it occurs:

  • Counting events or log messages.
  • Tracking items in inventories or carts.
  • Representing weighted choices or frequencies.
  • Implementing histograms or term frequencies.

@rimbu/multiset focuses on:

  • Element counts, not just membership – every value has an associated non‑negative count.
  • Immutable operations – updates return new instances, sharing structure internally.
  • Choice of backing map – hash‑based for speed, or sorted for deterministic value order.
  • Ergonomic API – familiar set‑like operations plus count‑aware helpers.

If you ever maintain a Map<T, number> (or object) to track counts manually, a MultiSet is usually a better fit.


Feature Highlights

  • Counts per element – each value can occur multiple times; counts are tracked in an internal map.
  • Distinct vs total sizesizeDistinct for unique values, size for total occurrences.
  • Hash & sorted variants – choose HashMultiSet for fast hashing or SortedMultiSet for deterministic ordering.
  • Immutable & persistent – structural sharing for fast copies and history‑friendly updates.
  • Configurable contexts – build custom configurations via MultiSet.createContext, HashMultiSet.createContext, or SortedMultiSet.createContext.
  • Rich operations – add/remove values, set or modify counts, bulk operations, streaming, and traversal utilities.

Quick Start

import { HashMultiSet } from '@rimbu/multiset';

// Create from individual values
const m = HashMultiSet.of('apple', 'banana', 'apple', 'orange');

// Total size vs number of distinct values
console.log(m.size); // 4
console.log(m.sizeDistinct); // 3

// Counts per element
console.log(m.count('apple')); // 2
console.log(m.count('banana')); // 1

// Updating counts returns a new multiset
const withMore = m.add('banana', 2);
console.log(withMore.count('banana')); // 3

Try Rimbu (including @rimbu/multiset) live in the browser using the Rimbu Sandbox on CodeSandbox.


Core Concepts & Types

Exported Types

From @rimbu/multiset:

| Name | Description | | ----------------------------- | -------------------------------------------------------------------------------------------- | | MultiSet<T> | Generic, type‑invariant multiset where values of type T can occur multiple times. | | MultiSet.NonEmpty<T> | Non‑empty refinement of MultiSet<T> with stronger guarantees. | | MultiSet.Context<UT> | Context/factory for creating MultiSet instances with configurable underlying map contexts. | | MultiSet.Builder<T> | Mutable builder for efficiently constructing a MultiSet before freezing it. | | VariantMultiSet<T> | Read‑only, type‑variant multiset; supports safe type‑widening but no mutating operations. | | VariantMultiSet.NonEmpty<T> | Non‑empty refinement of VariantMultiSet<T>. | | HashMultiSet<T> | Multiset backed by a HashMap for counts (hashed elements, fast unordered operations). | | HashMultiSet.Context<UT> | Context for HashMultiSet, exposing configuration and factories. | | HashMultiSet.Builder<T> | Builder type for HashMultiSet. | | SortedMultiSet<T> | Multiset backed by a SortedMap for counts (sorted elements, deterministic ordering). | | SortedMultiSet.Context<UT> | Context for SortedMultiSet. | | SortedMultiSet.Builder<T> | Builder type for SortedMultiSet. |

Key Operations (HashMultiSet)

import { HashMultiSet } from '@rimbu/multiset';

// Construction
const empty = HashMultiSet.empty<number>();
const fromValues = HashMultiSet.of(1, 2, 2, 3);

// Size & distinct size
empty.isEmpty; // true
fromValues.size; // 4
fromValues.sizeDistinct; // 3

// Lookups
fromValues.has(2); // true
fromValues.count(2); // 2
fromValues.count(10); // 0

// Updating (returns new MultiSet)
const withMore = fromValues.add(2); // add one more '2'
const withSetCount = fromValues.setCount(3, 5); // set exact count for value 3

// Removing occurrences
const removedSome = fromValues.remove(2, { amount: 1 });
const removedAll = fromValues.remove(2, { amount: 'ALL' });

See the full MultiSet docs and API reference for all operations.


Working with Hash & Sorted MultiSets

All concrete variants share the same MultiSet semantics but differ in how values are stored and ordered internally:

import { HashMultiSet, SortedMultiSet } from '@rimbu/multiset';

// Hash-based multiset (fast, unordered)
const hashMulti = HashMultiSet.of('b', 'a', 'b');
hashMulti.stream().toArray(); // order not guaranteed

// Sorted multiset (deterministic value order)
const sortedMulti = SortedMultiSet.of('b', 'a', 'b');
sortedMulti.stream().toArray(); // ['a', 'b', 'b']

// Working with streams of distinct values
sortedMulti.streamDistinct().toArray(); // ['a', 'b']

If you need custom underlying contexts (e.g. custom hashers or comparators), you can create them via HashMultiSet.createContext or SortedMultiSet.createContext:

import { HashMultiSet } from '@rimbu/multiset';

const context = HashMultiSet.createContext<number>({
  countMapContext: /* optional: custom RMap.Context<number> */,
});

const multi = context.of(1, 2, 2, 3);

For read‑only, type‑variant views that can be safely widened, use the VariantMultiSet interfaces exported from this package.


Performance Notes

  • MultiSets in Rimbu are built on persistent data structures – updates are typically \(O(\log n)\) and share most of their structure.
  • Lookups and updates behave similarly to the underlying HashMap / SortedMap implementations used for the internal count maps.
  • Many bulk operations accept generic StreamSource inputs, letting you construct and transform MultiSets efficiently from arrays, iterables, or streams.

For detailed performance characteristics and benchmarks, see the main Rimbu documentation at rimbu.org.


Installation

Node / Bun / npm / Yarn / Deno

npm install @rimbu/multiset
# or
yarn add @rimbu/multiset
# or
bun add @rimbu/multiset
# or
deno add npm:@rimbu/multiset

Browser / ESM

@rimbu/multiset 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 MultiSet different from a regular Set?
A MultiSet allows multiple occurrences per value and tracks their counts, while a regular Set only tracks membership and stores each value at most once.

Q: What happens if I add the same value multiple times?
The count for that value increases: add, addAll, or addEntries will raise its occurrence count instead of ignoring duplicates.

Q: Is the structure mutable?
No. All updates return new MultiSet instances; existing ones remain unchanged and can be safely shared across your application.

Q: Can I iterate values or distinct values separately?
Yes. Use stream() to iterate all occurrences and streamDistinct() to iterate each distinct value once.


Ecosystem & Integration

  • Part of the broader Rimbu collections ecosystem – interoperates with @rimbu/hashed, @rimbu/sorted, @rimbu/collection-types, and @rimbu/stream.
  • Ideal for modelling counters, tag frequencies, weighted selections, and other count‑based structures.
  • Works seamlessly with other Rimbu collections and utilities for building rich, immutable data models.

Explore more at the Rimbu documentation and the MultiSet 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. Logo © Rimbu.