Terable
Terable is a wonderful library for using ES2015 iterables.
The functions it provides are comparable to a subset of lodash, but:
- They accept iterables as input, and return iterables back (where appropriate)
- They're lazy where possible (extremely lazy in fact), and have a functional API similar to lodash/fp (no method chaining!)
- They're optimized to reduce the number of iterators and avoid creating intermediary data structures when composed together
- Flow types are built-in
While lodash is an incredible library for what it does, it's not inteded to support iterables directly (requiring you to convert them using spread syntax). [1] The limited support it has for lazy evaluation will also likely be cut from version 5. [1] [2]
As an alternative, you may also want to look into iterare if you prefer method chaining and TypeScript support (though the functionality doesn't overlap completely).
Setup
yarn add terable
import * as it from 'terable';// In Nodeconst it = require('terable'); // You can also import only the functions you needimport map from 'terable/map';// In Node (note it's the .default export)const map = require('terable/map').default;
The published source is transpiled to support Node 6 and IE11. However, you'll need some polyfills in IE11 and other browsers which don't support the following features:
Symbol.iterator
- Iterator support for arrays and strings
Set
(only fordifference
,intersect
,union
,uniq
, anduniqBy
)Map
(only forcountBy
,groupBy
,intersect
, andkeyBy
)
Generators aren't used, so you don't need the regenerator runtime to use this library.
Flow types are included with the package as separate *.js.flow
files which are picked up by Flow automatically.
API
All functions are curried.
Most return values are iterables which can't be reused (i.e. iterated more than once), though some functions return a Set
or Map
which can of course be reused.
For usage examples, have a look at the tests.
all : <T>(test: (T) => mixed) => (Iterable<T>) => boolean
any : <T>(test: (T) => mixed) => (Iterable<T>) => boolean
compact : <T>(Iterable<T>) => Iterable<$NonMaybeType<T>>
concat : <T>(Iterable <Iterable<T>>) => Iterable<T>
concatMap : <T, U>(func: (T) => Iterable<U>) => (Iterable<T>) => Iterable<U>
countBy : <T, K>(func: (T) => K) => (Iterable<T>) => Map<K, number>
difference : <T>(sets: Iterable<Iterable<T>>) => Set<T>
drop : (count: number) => <T>(Iterable<T>) => Iterable<T>
each : <T>(func: (T) => mixed) => (Iterable<T>) => void
filter : <T, U>(test: ((T | U)) => mixed) => (Iterable<(T | U)>) => Iterable<U>
find : <T>(func: (T) => mixed) => (Iterable<T>) => T
foldl : <T, U>(func: (U, T) => U) => (U) => (Iterable<T>) => U
groupBy : <T, K>(func: (T) => K) => (Iterable<T>) => Map<K, Array<T>>
head : <T>(Iterable<T>) => T
intersect : <T>(sets: Iterable<Iterable<T>>) => Set<T>
join : (sep: string) => (Iterable<string>) => string
keyBy : <T, K>(func: (T) => K) => (Iterable<T>) => Map<K, T>
map : <T, U>(func: (T) => U) => (Iterable<T>) => Iterable<U>
sort : <T>(Iterable<T>) => Iterable<T>
sortBy : <T, K>(func: (T) => K) => (Iterable<T>) => Iterable<T>
take : (count: number) => <T>(Iterable<T>) => Iterable<T>
toArray : <T>(Iterable<T>) => Array<T>
toObject : <K, T>(entries: Iterable<[K, T]>) => {[K]: T}
union : <T>(sets: Iterable<Iterable<T>>) => Set<T>
uniq : <T>(Iterable<T>) => Iterable<T>
uniqBy : <T, U>(func: (T) => U) => (Iterable<T>) => Iterable<T>
Benchmarks
You can take these with a grain of salt. I used the benchmarks specifically to measure the performance of large iterator chains. Terable is slower at iterare's own benchmarks, and it would be quite easy to construct micro-benchmarks where lodash is 100x faster.
The main takeaway from these is that Terable isn't half-bad.
michael@Michaels-MacBook-Pro-2 ~/c/terable> node --versionv10.12.0michael@Michaels-MacBook-Pro-2 ~/c/terable>