Spaces:
Build error
Build error
# Immutable collections for JavaScript | |
[](https://github.com/immutable-js/immutable-js/actions/workflows/ci.yml?query=branch%3Amain) [Chat on slack](https://immutable-js.slack.com) | |
[Read the docs](https://immutable-js.com) and eat your vegetables. | |
Docs are automatically generated from [README.md][] and [immutable.d.ts][]. | |
Please contribute! Also, don't miss the [wiki][] which contains articles on | |
additional specific topics. Can't find something? Open an [issue][]. | |
**Table of contents:** | |
- [Introduction](#introduction) | |
- [Getting started](#getting-started) | |
- [The case for Immutability](#the-case-for-immutability) | |
- [JavaScript-first API](#javascript-first-api) | |
- [Nested Structures](#nested-structures) | |
- [Equality treats Collections as Values](#equality-treats-collections-as-values) | |
- [Batching Mutations](#batching-mutations) | |
- [Lazy Seq](#lazy-seq) | |
- [Additional Tools and Resources](#additional-tools-and-resources) | |
- [Contributing](#contributing) | |
## Introduction | |
[Immutable][] data cannot be changed once created, leading to much simpler | |
application development, no defensive copying, and enabling advanced memoization | |
and change detection techniques with simple logic. [Persistent][] data presents | |
a mutative API which does not update the data in-place, but instead always | |
yields new updated data. | |
Immutable.js provides many Persistent Immutable data structures including: | |
`List`, `Stack`, `Map`, `OrderedMap`, `Set`, `OrderedSet` and `Record`. | |
These data structures are highly efficient on modern JavaScript VMs by using | |
structural sharing via [hash maps tries][] and [vector tries][] as popularized | |
by Clojure and Scala, minimizing the need to copy or cache data. | |
Immutable.js also provides a lazy `Seq`, allowing efficient | |
chaining of collection methods like `map` and `filter` without creating | |
intermediate representations. Create some `Seq` with `Range` and `Repeat`. | |
Want to hear more? Watch the presentation about Immutable.js: | |
[](https://youtu.be/I7IdS-PbEgI) | |
[README.md]: https://github.com/immutable-js/immutable-js/blob/main/README.md | |
[immutable.d.ts]: https://github.com/immutable-js/immutable-js/blob/main/type-definitions/immutable.d.ts | |
[wiki]: https://github.com/immutable-js/immutable-js/wiki | |
[issue]: https://github.com/immutable-js/immutable-js/issues | |
[Persistent]: https://en.wikipedia.org/wiki/Persistent_data_structure | |
[Immutable]: https://en.wikipedia.org/wiki/Immutable_object | |
[hash maps tries]: https://en.wikipedia.org/wiki/Hash_array_mapped_trie | |
[vector tries]: https://hypirion.com/musings/understanding-persistent-vector-pt-1 | |
## Getting started | |
Install `immutable` using npm. | |
```shell | |
npm install immutable | |
``` | |
Or install using yarn. | |
```shell | |
yarn add immutable | |
``` | |
Then require it into any module. | |
<!-- runkit:activate --> | |
```js | |
const { Map } = require('immutable'); | |
const map1 = Map({ a: 1, b: 2, c: 3 }); | |
const map2 = map1.set('b', 50); | |
map1.get('b') + ' vs. ' + map2.get('b'); // 2 vs. 50 | |
``` | |
### Browser | |
Immutable.js has no dependencies, which makes it predictable to include in a Browser. | |
It's highly recommended to use a module bundler like [webpack](https://webpack.github.io/), | |
[rollup](https://rollupjs.org/), or | |
[browserify](https://browserify.org/). The `immutable` npm module works | |
without any additional consideration. All examples throughout the documentation | |
will assume use of this kind of tool. | |
Alternatively, Immutable.js may be directly included as a script tag. Download | |
or link to a CDN such as [CDNJS](https://cdnjs.com/libraries/immutable) | |
or [jsDelivr](https://www.jsdelivr.com/package/npm/immutable). | |
Use a script tag to directly add `Immutable` to the global scope: | |
```html | |
<script src="immutable.min.js"></script> | |
<script> | |
var map1 = Immutable.Map({ a: 1, b: 2, c: 3 }); | |
var map2 = map1.set('b', 50); | |
map1.get('b'); // 2 | |
map2.get('b'); // 50 | |
</script> | |
``` | |
Or use an AMD-style loader (such as [RequireJS](https://requirejs.org/)): | |
```js | |
require(['./immutable.min.js'], function (Immutable) { | |
var map1 = Immutable.Map({ a: 1, b: 2, c: 3 }); | |
var map2 = map1.set('b', 50); | |
map1.get('b'); // 2 | |
map2.get('b'); // 50 | |
}); | |
``` | |
### Flow & TypeScript | |
Use these Immutable collections and sequences as you would use native | |
collections in your [Flowtype](https://flowtype.org/) or [TypeScript](https://typescriptlang.org) programs while still taking | |
advantage of type generics, error detection, and auto-complete in your IDE. | |
Installing `immutable` via npm brings with it type definitions for Flow (v0.55.0 or higher) | |
and TypeScript (v2.1.0 or higher), so you shouldn't need to do anything at all! | |
#### Using TypeScript with Immutable.js v4 | |
Immutable.js type definitions embrace ES2015. While Immutable.js itself supports | |
legacy browsers and environments, its type definitions require TypeScript's 2015 | |
lib. Include either `"target": "es2015"` or `"lib": "es2015"` in your | |
`tsconfig.json`, or provide `--target es2015` or `--lib es2015` to the | |
`tsc` command. | |
<!-- runkit:activate --> | |
```js | |
const { Map } = require('immutable'); | |
const map1 = Map({ a: 1, b: 2, c: 3 }); | |
const map2 = map1.set('b', 50); | |
map1.get('b') + ' vs. ' + map2.get('b'); // 2 vs. 50 | |
``` | |
#### Using TypeScript with Immutable.js v3 and earlier: | |
Previous versions of Immutable.js include a reference file which you can include | |
via relative path to the type definitions at the top of your file. | |
```js | |
///<reference path='./node_modules/immutable/dist/immutable.d.ts'/> | |
import Immutable from 'immutable'; | |
var map1: Immutable.Map<string, number>; | |
map1 = Immutable.Map({ a: 1, b: 2, c: 3 }); | |
var map2 = map1.set('b', 50); | |
map1.get('b'); // 2 | |
map2.get('b'); // 50 | |
``` | |
## The case for Immutability | |
Much of what makes application development difficult is tracking mutation and | |
maintaining state. Developing with immutable data encourages you to think | |
differently about how data flows through your application. | |
Subscribing to data events throughout your application creates a huge overhead of | |
book-keeping which can hurt performance, sometimes dramatically, and creates | |
opportunities for areas of your application to get out of sync with each other | |
due to easy to make programmer error. Since immutable data never changes, | |
subscribing to changes throughout the model is a dead-end and new data can only | |
ever be passed from above. | |
This model of data flow aligns well with the architecture of [React][] | |
and especially well with an application designed using the ideas of [Flux][]. | |
When data is passed from above rather than being subscribed to, and you're only | |
interested in doing work when something has changed, you can use equality. | |
Immutable collections should be treated as _values_ rather than _objects_. While | |
objects represent some thing which could change over time, a value represents | |
the state of that thing at a particular instance of time. This principle is most | |
important to understanding the appropriate use of immutable data. In order to | |
treat Immutable.js collections as values, it's important to use the | |
`Immutable.is()` function or `.equals()` method to determine _value equality_ | |
instead of the `===` operator which determines object _reference identity_. | |
<!-- runkit:activate --> | |
```js | |
const { Map } = require('immutable'); | |
const map1 = Map({ a: 1, b: 2, c: 3 }); | |
const map2 = Map({ a: 1, b: 2, c: 3 }); | |
map1.equals(map2); // true | |
map1 === map2; // false | |
``` | |
Note: As a performance optimization Immutable.js attempts to return the existing | |
collection when an operation would result in an identical collection, allowing | |
for using `===` reference equality to determine if something definitely has not | |
changed. This can be extremely useful when used within a memoization function | |
which would prefer to re-run the function if a deeper equality check could | |
potentially be more costly. The `===` equality check is also used internally by | |
`Immutable.is` and `.equals()` as a performance optimization. | |
<!-- runkit:activate --> | |
```js | |
const { Map } = require('immutable'); | |
const map1 = Map({ a: 1, b: 2, c: 3 }); | |
const map2 = map1.set('b', 2); // Set to same value | |
map1 === map2; // true | |
``` | |
If an object is immutable, it can be "copied" simply by making another reference | |
to it instead of copying the entire object. Because a reference is much smaller | |
than the object itself, this results in memory savings and a potential boost in | |
execution speed for programs which rely on copies (such as an undo-stack). | |
<!-- runkit:activate --> | |
```js | |
const { Map } = require('immutable'); | |
const map = Map({ a: 1, b: 2, c: 3 }); | |
const mapCopy = map; // Look, "copies" are free! | |
``` | |
[React]: https://reactjs.org/ | |
[Flux]: https://facebook.github.io/flux/docs/in-depth-overview/ | |
## JavaScript-first API | |
While Immutable.js is inspired by Clojure, Scala, Haskell and other functional | |
programming environments, it's designed to bring these powerful concepts to | |
JavaScript, and therefore has an Object-Oriented API that closely mirrors that | |
of [ES2015][] [Array][], [Map][], and [Set][]. | |
[es2015]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/ECMAScript_6_support_in_Mozilla | |
[array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array | |
[map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map | |
[set]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set | |
The difference for the immutable collections is that methods which would mutate | |
the collection, like `push`, `set`, `unshift` or `splice`, instead return a new | |
immutable collection. Methods which return new arrays, like `slice` or `concat`, | |
instead return new immutable collections. | |
<!-- runkit:activate --> | |
```js | |
const { List } = require('immutable'); | |
const list1 = List([1, 2]); | |
const list2 = list1.push(3, 4, 5); | |
const list3 = list2.unshift(0); | |
const list4 = list1.concat(list2, list3); | |
assert.equal(list1.size, 2); | |
assert.equal(list2.size, 5); | |
assert.equal(list3.size, 6); | |
assert.equal(list4.size, 13); | |
assert.equal(list4.get(0), 1); | |
``` | |
Almost all of the methods on [Array][] will be found in similar form on | |
`Immutable.List`, those of [Map][] found on `Immutable.Map`, and those of [Set][] | |
found on `Immutable.Set`, including collection operations like `forEach()` | |
and `map()`. | |
<!-- runkit:activate --> | |
```js | |
const { Map } = require('immutable'); | |
const alpha = Map({ a: 1, b: 2, c: 3, d: 4 }); | |
alpha.map((v, k) => k.toUpperCase()).join(); | |
// 'A,B,C,D' | |
``` | |
### Convert from raw JavaScript objects and arrays. | |
Designed to inter-operate with your existing JavaScript, Immutable.js | |
accepts plain JavaScript Arrays and Objects anywhere a method expects a | |
`Collection`. | |
<!-- runkit:activate --> | |
```js | |
const { Map, List } = require('immutable'); | |
const map1 = Map({ a: 1, b: 2, c: 3, d: 4 }); | |
const map2 = Map({ c: 10, a: 20, t: 30 }); | |
const obj = { d: 100, o: 200, g: 300 }; | |
const map3 = map1.merge(map2, obj); | |
// Map { a: 20, b: 2, c: 10, d: 100, t: 30, o: 200, g: 300 } | |
const list1 = List([1, 2, 3]); | |
const list2 = List([4, 5, 6]); | |
const array = [7, 8, 9]; | |
const list3 = list1.concat(list2, array); | |
// List [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] | |
``` | |
This is possible because Immutable.js can treat any JavaScript Array or Object | |
as a Collection. You can take advantage of this in order to get sophisticated | |
collection methods on JavaScript Objects, which otherwise have a very sparse | |
native API. Because Seq evaluates lazily and does not cache intermediate | |
results, these operations can be extremely efficient. | |
<!-- runkit:activate --> | |
```js | |
const { Seq } = require('immutable'); | |
const myObject = { a: 1, b: 2, c: 3 }; | |
Seq(myObject) | |
.map(x => x * x) | |
.toObject(); | |
// { a: 1, b: 4, c: 9 } | |
``` | |
Keep in mind, when using JS objects to construct Immutable Maps, that | |
JavaScript Object properties are always strings, even if written in a quote-less | |
shorthand, while Immutable Maps accept keys of any type. | |
<!-- runkit:activate --> | |
```js | |
const { fromJS } = require('immutable'); | |
const obj = { 1: 'one' }; | |
console.log(Object.keys(obj)); // [ "1" ] | |
console.log(obj['1'], obj[1]); // "one", "one" | |
const map = fromJS(obj); | |
console.log(map.get('1'), map.get(1)); // "one", undefined | |
``` | |
Property access for JavaScript Objects first converts the key to a string, but | |
since Immutable Map keys can be of any type the argument to `get()` is | |
not altered. | |
### Converts back to raw JavaScript objects. | |
All Immutable.js Collections can be converted to plain JavaScript Arrays and | |
Objects shallowly with `toArray()` and `toObject()` or deeply with `toJS()`. | |
All Immutable Collections also implement `toJSON()` allowing them to be passed | |
to `JSON.stringify` directly. They also respect the custom `toJSON()` methods of | |
nested objects. | |
<!-- runkit:activate --> | |
```js | |
const { Map, List } = require('immutable'); | |
const deep = Map({ a: 1, b: 2, c: List([3, 4, 5]) }); | |
console.log(deep.toObject()); // { a: 1, b: 2, c: List [ 3, 4, 5 ] } | |
console.log(deep.toArray()); // [ 1, 2, List [ 3, 4, 5 ] ] | |
console.log(deep.toJS()); // { a: 1, b: 2, c: [ 3, 4, 5 ] } | |
JSON.stringify(deep); // '{"a":1,"b":2,"c":[3,4,5]}' | |
``` | |
### Embraces ES2015 | |
Immutable.js supports all JavaScript environments, including legacy | |
browsers (even IE11). However it also takes advantage of features added to | |
JavaScript in [ES2015][], the latest standard version of JavaScript, including | |
[Iterators][], [Arrow Functions][], [Classes][], and [Modules][]. It's inspired | |
by the native [Map][] and [Set][] collections added to ES2015. | |
All examples in the Documentation are presented in ES2015. To run in all | |
browsers, they need to be translated to ES5. | |
```js | |
// ES2015 | |
const mapped = foo.map(x => x * x); | |
// ES5 | |
var mapped = foo.map(function (x) { | |
return x * x; | |
}); | |
``` | |
All Immutable.js collections are [Iterable][iterators], which allows them to be | |
used anywhere an Iterable is expected, such as when spreading into an Array. | |
<!-- runkit:activate --> | |
```js | |
const { List } = require('immutable'); | |
const aList = List([1, 2, 3]); | |
const anArray = [0, ...aList, 4, 5]; // [ 0, 1, 2, 3, 4, 5 ] | |
``` | |
Note: A Collection is always iterated in the same order, however that order may | |
not always be well defined, as is the case for the `Map` and `Set`. | |
[Iterators]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/The_Iterator_protocol | |
[Arrow Functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions | |
[Classes]: https://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes | |
[Modules]: https://www.2ality.com/2014/09/es6-modules-final.html | |
## Nested Structures | |
The collections in Immutable.js are intended to be nested, allowing for deep | |
trees of data, similar to JSON. | |
<!-- runkit:activate --> | |
```js | |
const { fromJS } = require('immutable'); | |
const nested = fromJS({ a: { b: { c: [3, 4, 5] } } }); | |
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ] } } } | |
``` | |
A few power-tools allow for reading and operating on nested data. The | |
most useful are `mergeDeep`, `getIn`, `setIn`, and `updateIn`, found on `List`, | |
`Map` and `OrderedMap`. | |
<!-- runkit:activate --> | |
```js | |
const { fromJS } = require('immutable'); | |
const nested = fromJS({ a: { b: { c: [3, 4, 5] } } }); | |
const nested2 = nested.mergeDeep({ a: { b: { d: 6 } } }); | |
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 6 } } } | |
console.log(nested2.getIn(['a', 'b', 'd'])); // 6 | |
const nested3 = nested2.updateIn(['a', 'b', 'd'], value => value + 1); | |
console.log(nested3); | |
// Map { a: Map { b: Map { c: List [ 3, 4, 5 ], d: 7 } } } | |
const nested4 = nested3.updateIn(['a', 'b', 'c'], list => list.push(6)); | |
// Map { a: Map { b: Map { c: List [ 3, 4, 5, 6 ], d: 7 } } } | |
``` | |
## Equality treats Collections as Values | |
Immutable.js collections are treated as pure data _values_. Two immutable | |
collections are considered _value equal_ (via `.equals()` or `is()`) if they | |
represent the same collection of values. This differs from JavaScript's typical | |
_reference equal_ (via `===` or `==`) for Objects and Arrays which only | |
determines if two variables represent references to the same object instance. | |
Consider the example below where two identical `Map` instances are not | |
_reference equal_ but are _value equal_. | |
<!-- runkit:activate --> | |
```js | |
// First consider: | |
const obj1 = { a: 1, b: 2, c: 3 }; | |
const obj2 = { a: 1, b: 2, c: 3 }; | |
obj1 !== obj2; // two different instances are always not equal with === | |
const { Map, is } = require('immutable'); | |
const map1 = Map({ a: 1, b: 2, c: 3 }); | |
const map2 = Map({ a: 1, b: 2, c: 3 }); | |
map1 !== map2; // two different instances are not reference-equal | |
map1.equals(map2); // but are value-equal if they have the same values | |
is(map1, map2); // alternatively can use the is() function | |
``` | |
Value equality allows Immutable.js collections to be used as keys in Maps or | |
values in Sets, and retrieved with different but equivalent collections: | |
<!-- runkit:activate --> | |
```js | |
const { Map, Set } = require('immutable'); | |
const map1 = Map({ a: 1, b: 2, c: 3 }); | |
const map2 = Map({ a: 1, b: 2, c: 3 }); | |
const set = Set().add(map1); | |
set.has(map2); // true because these are value-equal | |
``` | |
Note: `is()` uses the same measure of equality as [Object.is][] for scalar | |
strings and numbers, but uses value equality for Immutable collections, | |
determining if both are immutable and all keys and values are equal | |
using the same measure of equality. | |
[object.is]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is | |
#### Performance tradeoffs | |
While value equality is useful in many circumstances, it has different | |
performance characteristics than reference equality. Understanding these | |
tradeoffs may help you decide which to use in each case, especially when used | |
to memoize some operation. | |
When comparing two collections, value equality may require considering every | |
item in each collection, on an `O(N)` time complexity. For large collections of | |
values, this could become a costly operation. Though if the two are not equal | |
and hardly similar, the inequality is determined very quickly. In contrast, when | |
comparing two collections with reference equality, only the initial references | |
to memory need to be compared which is not based on the size of the collections, | |
which has an `O(1)` time complexity. Checking reference equality is always very | |
fast, however just because two collections are not reference-equal does not rule | |
out the possibility that they may be value-equal. | |
#### Return self on no-op optimization | |
When possible, Immutable.js avoids creating new objects for updates where no | |
change in _value_ occurred, to allow for efficient _reference equality_ checking | |
to quickly determine if no change occurred. | |
<!-- runkit:activate --> | |
```js | |
const { Map } = require('immutable'); | |
const originalMap = Map({ a: 1, b: 2, c: 3 }); | |
const updatedMap = originalMap.set('b', 2); | |
updatedMap === originalMap; // No-op .set() returned the original reference. | |
``` | |
However updates which do result in a change will return a new reference. Each | |
of these operations occur independently, so two similar updates will not return | |
the same reference: | |
<!-- runkit:activate --> | |
```js | |
const { Map } = require('immutable'); | |
const originalMap = Map({ a: 1, b: 2, c: 3 }); | |
const updatedMap = originalMap.set('b', 1000); | |
// New instance, leaving the original immutable. | |
updatedMap !== originalMap; | |
const anotherUpdatedMap = originalMap.set('b', 1000); | |
// Despite both the results of the same operation, each created a new reference. | |
anotherUpdatedMap !== updatedMap; | |
// However the two are value equal. | |
anotherUpdatedMap.equals(updatedMap); | |
``` | |
## Batching Mutations | |
> If a tree falls in the woods, does it make a sound? | |
> | |
> If a pure function mutates some local data in order to produce an immutable | |
> return value, is that ok? | |
> | |
> — Rich Hickey, Clojure | |
Applying a mutation to create a new immutable object results in some overhead, | |
which can add up to a minor performance penalty. If you need to apply a series | |
of mutations locally before returning, Immutable.js gives you the ability to | |
create a temporary mutable (transient) copy of a collection and apply a batch of | |
mutations in a performant manner by using `withMutations`. In fact, this is | |
exactly how Immutable.js applies complex mutations itself. | |
As an example, building `list2` results in the creation of 1, not 3, new | |
immutable Lists. | |
<!-- runkit:activate --> | |
```js | |
const { List } = require('immutable'); | |
const list1 = List([1, 2, 3]); | |
const list2 = list1.withMutations(function (list) { | |
list.push(4).push(5).push(6); | |
}); | |
assert.equal(list1.size, 3); | |
assert.equal(list2.size, 6); | |
``` | |
Note: Immutable.js also provides `asMutable` and `asImmutable`, but only | |
encourages their use when `withMutations` will not suffice. Use caution to not | |
return a mutable copy, which could result in undesired behavior. | |
_Important!_: Only a select few methods can be used in `withMutations` including | |
`set`, `push` and `pop`. These methods can be applied directly against a | |
persistent data-structure where other methods like `map`, `filter`, `sort`, | |
and `splice` will always return new immutable data-structures and never mutate | |
a mutable collection. | |
## Lazy Seq | |
`Seq` describes a lazy operation, allowing them to efficiently chain | |
use of all the higher-order collection methods (such as `map` and `filter`) | |
by not creating intermediate collections. | |
**Seq is immutable** — Once a Seq is created, it cannot be | |
changed, appended to, rearranged or otherwise modified. Instead, any mutative | |
method called on a `Seq` will return a new `Seq`. | |
**Seq is lazy** — `Seq` does as little work as necessary to respond to any | |
method call. Values are often created during iteration, including implicit | |
iteration when reducing or converting to a concrete data structure such as | |
a `List` or JavaScript `Array`. | |
For example, the following performs no work, because the resulting | |
`Seq`'s values are never iterated: | |
```js | |
const { Seq } = require('immutable'); | |
const oddSquares = Seq([1, 2, 3, 4, 5, 6, 7, 8]) | |
.filter(x => x % 2 !== 0) | |
.map(x => x * x); | |
``` | |
Once the `Seq` is used, it performs only the work necessary. In this | |
example, no intermediate arrays are ever created, filter is called three | |
times, and map is only called once: | |
```js | |
oddSquares.get(1); // 9 | |
``` | |
Any collection can be converted to a lazy Seq with `Seq()`. | |
<!-- runkit:activate --> | |
```js | |
const { Map, Seq } = require('immutable'); | |
const map = Map({ a: 1, b: 2, c: 3 }); | |
const lazySeq = Seq(map); | |
``` | |
`Seq` allows for the efficient chaining of operations, allowing for the | |
expression of logic that can otherwise be very tedious: | |
```js | |
lazySeq | |
.flip() | |
.map(key => key.toUpperCase()) | |
.flip(); | |
// Seq { A: 1, B: 2, C: 3 } | |
``` | |
As well as expressing logic that would otherwise seem memory or time | |
limited, for example `Range` is a special kind of Lazy sequence. | |
<!-- runkit:activate --> | |
```js | |
const { Range } = require('immutable'); | |
Range(1, Infinity) | |
.skip(1000) | |
.map(n => -n) | |
.filter(n => n % 2 === 0) | |
.take(2) | |
.reduce((r, n) => r * n, 1); | |
// 1006008 | |
``` | |
## Comparison of filter(), groupBy(), and partition() | |
The `filter()`, `groupBy()`, and `partition()` methods are similar in that they | |
all divide a collection into parts based on applying a function to each element. | |
All three call the predicate or grouping function once for each item in the | |
input collection. All three return zero or more collections of the same type as | |
their input. The returned collections are always distinct from the input | |
(according to `===`), even if the contents are identical. | |
Of these methods, `filter()` is the only one that is lazy and the only one which | |
discards items from the input collection. It is the simplest to use, and the | |
fact that it returns exactly one collection makes it easy to combine with other | |
methods to form a pipeline of operations. | |
The `partition()` method is similar to an eager version of `filter()`, but it | |
returns two collections; the first contains the items that would have been | |
discarded by `filter()`, and the second contains the items that would have been | |
kept. It always returns an array of exactly two collections, which can make it | |
easier to use than `groupBy()`. Compared to making two separate calls to | |
`filter()`, `partition()` makes half as many calls it the predicate passed to | |
it. | |
The `groupBy()` method is a more generalized version of `partition()` that can | |
group by an arbitrary function rather than just a predicate. It returns a map | |
with zero or more entries, where the keys are the values returned by the | |
grouping function, and the values are nonempty collections of the corresponding | |
arguments. Although `groupBy()` is more powerful than `partition()`, it can be | |
harder to use because it is not always possible predict in advance how many | |
entries the returned map will have and what their keys will be. | |
| Summary | `filter` | `partition` | `groupBy` | | |
|:------------------------------|:---------|:------------|:---------------| | |
| ease of use | easiest | moderate | hardest | | |
| generality | least | moderate | most | | |
| laziness | lazy | eager | eager | | |
| # of returned sub-collections | 1 | 2 | 0 or more | | |
| sub-collections may be empty | yes | yes | no | | |
| can discard items | yes | no | no | | |
| wrapping container | none | array | Map/OrderedMap | | |
## Additional Tools and Resources | |
- [Atom-store](https://github.com/jameshopkins/atom-store/) | |
- A Clojure-inspired atom implementation in Javascript with configurability | |
for external persistance. | |
- [Chai Immutable](https://github.com/astorije/chai-immutable) | |
- If you are using the [Chai Assertion Library](https://chaijs.com/), this | |
provides a set of assertions to use against Immutable.js collections. | |
- [Fantasy-land](https://github.com/fantasyland/fantasy-land) | |
- Specification for interoperability of common algebraic structures in JavaScript. | |
- [Immutagen](https://github.com/pelotom/immutagen) | |
- A library for simulating immutable generators in JavaScript. | |
- [Immutable-cursor](https://github.com/redbadger/immutable-cursor) | |
- Immutable cursors incorporating the Immutable.js interface over | |
Clojure-inspired atom. | |
- [Immutable-ext](https://github.com/DrBoolean/immutable-ext) | |
- Fantasyland extensions for immutablejs | |
- [Immutable-js-tools](https://github.com/madeinfree/immutable-js-tools) | |
- Util tools for immutable.js | |
- [Immutable-Redux](https://github.com/gajus/redux-immutable) | |
- redux-immutable is used to create an equivalent function of Redux | |
combineReducers that works with Immutable.js state. | |
- [Immutable-Treeutils](https://github.com/lukasbuenger/immutable-treeutils) | |
- Functional tree traversal helpers for ImmutableJS data structures. | |
- [Irecord](https://github.com/ericelliott/irecord) | |
- An immutable store that exposes an RxJS observable. Great for React. | |
- [Mudash](https://github.com/brianneisler/mudash) | |
- Lodash wrapper providing Immutable.JS support. | |
- [React-Immutable-PropTypes](https://github.com/HurricaneJames/react-immutable-proptypes) | |
- PropType validators that work with Immutable.js. | |
- [Redux-Immutablejs](https://github.com/indexiatech/redux-immutablejs) | |
- Redux Immutable facilities. | |
- [Rxstate](https://github.com/yamalight/rxstate) | |
- Simple opinionated state management library based on RxJS and Immutable.js. | |
- [Transit-Immutable-js](https://github.com/glenjamin/transit-immutable-js) | |
- Transit serialisation for Immutable.js. | |
- See also: [Transit-js](https://github.com/cognitect/transit-js) | |
Have an additional tool designed to work with Immutable.js? | |
Submit a PR to add it to this list in alphabetical order. | |
## Contributing | |
Use [Github issues](https://github.com/immutable-js/immutable-js/issues) for requests. | |
We actively welcome pull requests, learn how to [contribute](https://github.com/immutable-js/immutable-js/blob/main/.github/CONTRIBUTING.md). | |
Immutable.js is maintained within the [Contributor Covenant's Code of Conduct](https://www.contributor-covenant.org/version/2/0/code_of_conduct/). | |
### Changelog | |
Changes are tracked as [Github releases](https://github.com/immutable-js/immutable-js/releases). | |
### License | |
Immutable.js is [MIT-licensed](./LICENSE). | |
### Thanks | |
[Phil Bagwell](https://www.youtube.com/watch?v=K2NYwP90bNs), for his inspiration | |
and research in persistent data structures. | |
[Hugh Jackson](https://github.com/hughfdjackson/), for providing the npm package | |
name. If you're looking for his unsupported package, see [this repository](https://github.com/hughfdjackson/immutable). | |