@voltra/streamz
v1.0.2
Published
Collection manipulation library that uses lazy evaluation for performances
Downloads
1
Maintainers
Readme
What is Streamz?
Streamz was a project made purely as a playground to look for ideas and ways to implement actual lazy evaluation of collection manipulations. It turns out this is a fairly usable implementation and could actually make a nice library.
Streamz is mainly inspired by C#'s LINQ, Java 8's Stream API, Rust's iter, Kotlin's sequences, C++'s Range-v3 and finally sequency.
How to install Streamz?
First you need to install it via NPM : npm i -S @voltra/streamz
Streamz does not provide a direct "plug into browser" file yet so you'll be required to use a build system (if you are targeting browsers).
Once installed, you can simply require/import it :
import { Stream } from "@voltra/streamz"
What does Streamz provide?
Streamz was fully developed using typescript, therefore you have access to the entire source code in the src
directory.
The entry point dist/index.js
provides the following :
import {
Stream,
Packer,
KeyGen,
ValueGen,
emptyPayloadValue,
isPayloadValueEmpty,
streamIsValidValue,
invalidStreamIteratorPayload
} from "@voltra/streamz"
Stream
is the class used for collection manipulation, it provides factoriesPacker
is used to transform aStream
into a collection (e.g. an array, an object, aMap
, aSet
, etc...)KeyGen
is an helper object that contains functions destined to be used inPacker#toObject
and similar methodsValueGen
is an helper object that contains functions destined to be used inPacker#toObject
and similar methodsemptyPayloadValue
is a globalSymbol
use to mark invalid payloadsisPayloadValueEmpty
is a function that checks whether or not the given value is one of an invalid payloadstreamIsValidValue
is a function that checks whether or not the given value is valid (not from an invalid payload)invalidStreamIteratorPayload
is a factory for invalid payloads
src/index.ts
provides the following :
import {
Stream,
Packer,
KeyGen,
ValueGen,
emptyPayloadValue,
isPayloadValueEmpty,
streamIsValidValue,
invalidStreamIteratorPayload,
BaseStreamIterator,
EndStreamIterator,
StreamIteratorPayload
} from "@voltra/streamz/src/index"
BaseStreamIterator
is an interface that represents both first and intermediate iterators in the iterator chain (i.e. operation chain)EndStreamIterator
is an interface that represents the final iterator in the iterator chain (i.e. operation chain)StreamIteratorPayload
is an interface that represents the payload retrieved when callingnext
on an iterator
Helper types are provided under src/types
(function.d.ts
and helpers.d.ts
).
Examples
import { Stream, KeyGen, ValueGen } from "@voltra/streamz"
Stream.of(1, 2, 3, 4) //Stream{1, 2, 3, 4}
.map(x => x+1) //Stream{2, 3, 4, 5}
.filter(x => x%2) //Stream{3, 5}
.pack.toArray(); //[3, 5]
Stream.fromObject({hello: "world", wombo: "combo"})
.map(([k, v]) => ([`key(${k})`, `value(${v})`]))
.pack.toObject(KeyGen.entries, ValueGen.entries);
//Stream{["hello", "world"], ["wombo", "combo"]}
//Stream{["key(hello)", "value(world)"], ["key(wombo)", "value(combo)"]}
//{"key(wombo)": "value(combo)", "key(hello)": "value(world)"}
Stream.of(1, 2, 1, 1, 2, 1) //Stream{1, 2, 1, 1, 2, 1}
.map(x => x+1) //Stream{2, 3, 2, 2, 3, 2}
.unique() //Stream{2, 3}
.pack.toArray(); //[2, 3]
Stream.of(2, 4, 6, 8) //Stream{2, 4, 6, 8}
.map(x => x+1) //Stream{3, 5, 7, 9}
.all(x => x%2); //true
import { Stream } from "@voltra/streamz"
const X = Stream.of(1, 2, 3, 4)
.map(x => x+1)
.filter(x => x%2)
.pack.toArray();
console.log(X);
//Is roughly equivalent to
const X = [];
for(const it in [1, 2, 3, 4]){
const x = it+1;
if(x % 2)
X.push(x);
}
console.log(X);
Changes
A complete JSDoc will be provided once ready.
v1.0.2
extend
in src/extend.ts
(also exported in src/index.ts
and therefore in dist/index.js
) :
- Installs global prototype extensions :
Array#stream()
isStream.from(this)
Object#stream()
isStream.fromObject(this)
Set#stream()
isStream.fromSet(this)
Map#stream()
isStream.fromMap(this)
- And class methods extensions
Object.fromStreams
isStream.zipToObject
Number.range
isStream.range
Number.infiniteRange
isStream.infinite
Compare
in src/utils.ts
(also exported in src/index.ts
and therefore in dist/index.js
) :
Compare.asc(lhs, rhs)
standard comparison function (ascending)Compare.desc(lhs, rhs)
standard comparison function (descending)Compare.mapped
"namespace" for mapped comparison functionsCompare.mapped.asc(mapper)
crafts aCompare#asc
where elements were mapped usingmapper
Compare.mapped.desc(mapper)
crafts aCompare#desc
where elements were mapped usingmapper
Stream
initial operations :
Stream.fromMap(map)
creates a stream from aMap
Stream.fromSet(set)
creates a stream from aSet
Stream
intermediate operations :
- Regular
Stream#chunked(size = 3)
groups items in chunks whose size is at mostsize
- Zipping
Stream#zip(stream)
combines this stream (makes a pair using one item from each stream)Stream.zip(lhs, rhs)
same aslhs.zip(rhs)
Stream#zipBy(stream, mapper)
combines this stream using the mapper function to craft the new itemStream.zipBy(lhs, rhs, mapper)
same aslhs.zipBy(rhs, mapper)
- Filtering
Stream#nonNull()
filters out anynull
Stream#nonFalsy()
filters out any falsy value (0
,null
,undefined
, etc...)Stream#filterNot(predicate)
filters element that satisfy the predicateStream#filterOut(predicate)
alias forStream#filterNot(predicate)
Stream#filterIsInstance(class)
filters out elements that are not instance ofclass
- Index manipulation
Stream#takeWhile(predicate)
keeps item untilpredicate
is not satisfiedStream#takeUntil(predicate)
keeps item whilepredicate
is not satisfied
Stream
terminal operations :
- Regular
Stream#count(predicate = (_ => true))
counts the elements that satisfy the predicate
- Predicate tests
Stream#contains(elem)
checks whether or notelem
is an item of this stream
- Index based
Stream#atIndex(index)
retrieves the element at the given index (or null if there is none)Stream#atIndexOr(index, default)
retrieves the element or get backdefault
Stream#first()
retrieves the first element (ornull
)Stream#firstOr(default)
retrieves the first element (ordefault
)
- Zipping
Stream#zipToObject(stream)
zips into an object usingthis
as keys andstream
as valuesStream.zipToObject(keys, values)
equivalent tokeys.zipToObject(values)
Stream#unzip()
unzips a stream of pairs into a pair of arraysStream#unzipBy(firstGen, lastGen)
unzips a stream into a pair of arrays applyingfirstGen
for the first element of the pair andlastGen
for the last element of the pairStream#unzipVia(mapper)
convenience method to unzip a stream of pairs into a pair of arrays using a single mapper function that returns a pair
- Sorting
Stream#sortedWith(comparator)
packs to an array sorted usingcomparator
as the comparison functionStream#sortedBy(mapper)
maps the objects and sort in ascending order via regular comparison operatorsStream#sortedDescBy(mapper)
same assortedBy
but in descending orderStream#sorted()
same assortedBy
but without mappingStream#sortedDesc()
same assorted
but in descending order
v1.0.1 and inferior
Factories (creators)
Streamz is not a usual object, it doesn't really expect you to call its constructor, it provides a lot of static factory methods in order for you to get the most fluent experience possible :
Stream.of(...args)
takes any amount of parameters and makes a stream out of itStream.from(args)
takes an array and makes a stream out of itStream.fromObject(obj)
takes an object and makes a stream out of itStream.range(higher)
takes a number used as its lower bound makes the range [0 ; higher) as a streamStream.range(lower, higher, step = 1)
takes both bounds, the step and makes the range [lower ; higher) as a stream (usesstep
as increment instead of 1)Stream.infinite(lower = 0)
makes a stream for the range [lower ; Infinity)
Intermediate computations (intermediary)
Streamz offers a lot of intermediate computations, these are not effective until a blocking computation is requested :
Stream#map(mapper)
maps each element using the provided mapper functionStream#filter(predicate)
only gives back elements that satisfy the provided predicateStream#peek(functor)
applies the function on each element and passes itStream#unique()
removes duplicates (uses aSet
behind the scenes to check for duplicates)Stream#take(amount = 10)
only keeps the firstx ≤ amount
elementsStream#skip(amount = 10)
skips the firstx ≤ amount
elementsStream#between(begin = 0, end = 10, excludeRight = false)
takes the element whose index is in the range [begin ; end] ifexcludeRight == false
otherwise from [begin ; end)
Blocking computations (terminators)
Operations
Common
Stream#forEach(functor)
applies the provided function on each elementStream#reduce(reducer, acc)
computes the reduced value by getting a newacc
by applying the reducer function and the currentacc
and the current element
Predicative
Stream#all(predicate)
checks whether or not every element satisfies the given predicateStream#any(predicate)
checks whether or not any element satisfies the given predicateStream#none(predicate)
checks whether or not none of the elements satisfies the given predicate
Packing
Stream#pack
is an instance of Packer
and exposes the following :
Packer#toArray()
converts the stream into an arrayPacker#toObjectBy(keyGen)
converts the stream into an object whose keys are generated usingkeyGen
on the current element and whose values are the elements of the streamPacker#toObject(keyGen, valueGen)
converts the stream into an object whose keys and values are generated using the current element onkeyGen
andvalueGen
Packer#toSet()
converts the stream into aSet
Packer#toMapBy(keyGen)
converts the stream into aMap
whose keys are generated usingkeyGen
on the current element and whose values are the elements of the streamPacker#toMap(keyGen, valueGen)
converts the stream into aMap
whose keys and values are generated using the current element onkeyGen
andvalueGen