iterablefu
Version:
Small, chainable, set of functions like range, map, reduce, filter, zip, for iterable objects.
236 lines (171 loc) • 8.26 kB
Markdown
# IterableFu
`IterableFu` is a small (1.2kb minimized and gzipped) library of functions like range, map, reduce, filter, zip, for iterable objects.
`IterableFu` has a chainable class to make it easy to chain iterable transforms. There is a chainable class factory
[makeChainableIterable](docs/makechainable.md), so you easily can add methods, or reduce bundle size.
## Features
* Chainable: `chainable([0, 1, 2]).map(x => 2*x).toArray()`.
* Works with your generators (and iterables): `chainable(yourGenerator()).mapWith(yourTransformGenerator)`.
* Customizable [makeChainableIterable](docs/makechainable.md), to add methods or reduce bundle sizes.
* Functional API takes data last, so you can curry, pipe and compose with your functional library.
* Exports both CommonJS and ES modules - dual package.
If you want asynchronous iterables along with task pool, event queue, pub/sub, merge, chunk, throttle, and the like, checkout [await-for-it](https://github.com/toolbuilder/await-for-it#readme).
## Table of Contents
<!-- !toc (minlevel=2 omit="Features;Table of Contents") -->
* [Installation](#installation)
* [Getting Started](#getting-started)
* [API](#api)
* [Examples](#examples)
* [Basics](#basics)
* [One Time Use](#one-time-use)
* [Iterablefu and Your Generators](#iterablefu-and-your-generators)
* [Smaller Bundles](#smaller-bundles)
* [Customization](#customization)
* [Alternatives](#alternatives)
* [Contributing](#contributing)
* [Issues](#issues)
* [License](#license)
<!-- toc! -->
## Installation
```bash
npm install --save iterablefu
```
## Getting Started
If you want the chainable API, use this import.
```javascript
import { chainable } from 'iterablefu'
```
```javascript
import { chainable } from 'iterablefu'
const iterable = chainable([1, 2, 3, 4, 5, 6]) // <-- throw any synchronous iterable in here
.filter(x => x % 2 === 0) // filters out odd numbers
.map(x => 2 * x)
console.log(Array.from(iterable)) // prints [4, 8, 12]
```
The most used methods are probably: `zip`, `zipAll`, `filter`, `flatten`, `map`, and `reduce`.
The documentation has an example for each method:
* [chainable](docs/chainable.md)- Is a factory that starts the chain and produces a `ChainableIterable`
* [ChainableIterable](docs/ChainableIterable.md) - For all the transforms and reducer methods
If you want the functional API, use this import.
```javascript
import { generators, transforms, reducers } from 'iterablefu'
```
You may also specify the modules directly to reduce bundle sizes. See more in the
[Smaller Bundles](#smaller-bundles) section.
## API
* Chainable API
* [Chainable factory](docs/chainable.md), factory functions that produce `ChainableIterable` instances
* [ChainableIterable](docs/ChainableIterable.md), chainable iterable generators, transforms, and reducers
* [Custom chainables](docs/makechainable.md), create custom chainable iterables
* Functional API
* [Generators](docs/generators.md), generator functions to create iterable sequences
* [Transforms](docs/transforms.md), functions to convert an iterable into another iterable (e.g. map, filter)
* [Reducers](docs/reducers.md), functions to convert an iterable into a value
## Examples
### Basics
`IterableFu` provides three basic categories of functions:
* **Generators** - create an iterable sequence
* **Transforms** - convert one iterable sequence into another
* **Reducers** - convert an iterable sequence into a value
Here's a quick example showing `range` (a generator), `map` (a transform), and `reduce` (a reducer).
```javascript
import { chainable } from 'iterablefu'
const answer =
chainable
.range(5) // generates 0, 1, 2, 3, 4
.map(x => 2 * x) // maps to 0, 2, 4, 6, 8
.reduce((a, x) => a + x, 0) // 0 + 2 + 4 + 6 + 8 = 20
console.log(answer) // prints 20
```
Some generators can convert Arrays or any other iterable into chainable iterables.
```javascript
const d = chainable([1, 2, 3]) // makes a chainable version of [1, 2, 3]
const e = chainable.concatenate([0, 1, 2], [3, 4]) // becomes [0, 1, 2, 3, 4]
const f = chainable.zip([1, 2, 3], ['a', 'b', 'c']) // becomes [[1, 'a'], [2, 'b'], [3, 'c']]
```
There are several ways to convert back to Arrays.
```javascript
const a = Array.from(chainable.range(5)) // a has the value [0, 1, 2, 3, 4, 5]
const b = [...chainable.range(3)] // b has the value [0, 1, 2]
const c = chainable.range(2, 5).toArray() // c has the value [2, 3, 4, 5, 6]
```
### One Time Use
Except for one method, `repeatIterable`, `IterableFu` only supports one-time iteration. This is because
iterators cannot be reused once done.
An iterable class like Array, can be iterated more than once because it produces a new iterator for each iteration.
```javascript
// IterableFu produces one-time use sequences
const a = chainable.range(5)
console.log([...a]) // print [0, 1, 2, 3, 4], iterator is now done
console.log([...a]) // prints [] because the iterator was done before the call
```
To reuse an `IterableFu` chain, wrap it in a function so that a new Generator object is returned each time it is called.
```javascript
const fn = () => chainable.range(5)
// Note the function calls below...
console.log([...fn()]) // prints [0, 1, 2, 3, 4]
console.log([...fn()]) // prints [0, 1, 2, 3, 4] because a new iterator was used
```
### Iterablefu and Your Generators
To use a generator function that creates a sequence, use [chainable](docs/chainable.md) as a function.
```javascript
// A simple generator function
const fn = function * (length) {
for (let i = 0; i < length; i++) {
yield i
}
}
// be sure to call the generator, don't just pass the function
const a = chainable(fn(3))
console.log([...a]) // prints [0, 1, 2]
```
To use a generator that transforms a sequence, use `mapWith`.
```javascript
// An example generator that transforms another sequence.
const fn = function * (n, iterable) {
for (let x of iterable) {
yield n * x
}
}
const input = [0, 1, 2, 3, 4]
// mapWith only accepts generator functions that have one parameter: iterable.
// If your generator takes additional parameters beyond iterable, you need
// to wrap it with another function that takes only one parameter. Like this:
const wrapper = (iterable) => fn(3, iterable)
const a = chainable(input).mapWith(wrapper).toArray()
console.log(a) // prints [0, 3, 6, 9, 12]
```
## Smaller Bundles
You can potentially reduce bundle size by importing the generators and function you want to use directly.
```javascript
import { zip, zipAll } from 'iterablefu/src/generators.js'
import { filter, flatten, map } from 'iterablefu/src/transfroms.js'
import { reduce } from 'iterablefu/src/reducers.js'
```
If you want a reduced size chainable object, use [makeChainableIterable](docs/makechainable.md) with the
directly imported functions. Customization is covered more completely in the `makeChainableIterable` docs.
```javascript
// using the imports from above
import { makeChainableIterable } from 'iterablefu/src/makechainable.js'
const generators = { zip, zipAll }
const transforms = { filter, flatten, map }
const reducers = { reduce }
const chainable = makeChainableIterable(generators, transforms, reducers)
```
## Customization
Customization is covered in the [makeChainableIterable](docs/makechainable.md) documentation.
## Alternatives
There are lots of alternatives:
* [wu](https://github.com/fitzgen/wu.js) - has many more methods than `IterableFu`. Does not use ES6 modules.
* [itiri](https://github.com/labs42io/itiriri) - many functions that force conversion to array. Typescript.
* [lazy.js](https://github.com/dtao/lazy.js/) - more methods, does not use generators
* [linq.js](https://github.com/mihaifm/linq) - LINQ (a .NET library) for JavaScript
* [GenSequence](https://github.com/Jason3S/GenSequence) - similar to `IterableFu`. Typescript.
... and many more.
## Contributing
Contributions are welcome. Please create a pull request.
I use [pnpm](https://pnpm.js.org/) instead of npm.
Automated browser tests use electron. Automated package tests build a `*.tgz` package and run tweaked unit tests in a temporary directory. Use `pnpm run build` to run everything in the right order.
## Issues
This project uses Github issues.
## License
MIT