0.5.7 • Published 4 years ago

lazystream.ts v0.5.7

Weekly downloads
1
License
MIT
Repository
github
Last release
4 years ago

LazyStream.TS

Inspired by Java 8 Streams and .NET LINQ, this small library provides an easy way to work with collections in FP-like and SQL-like styles.

Class: Stream <T>

Stream class that wraps Iterable<T> and provides most of the common FP-style operations like map, filter, flatMap etc. as well as SQL-style select, where, join etc. Stream does also implement Iterable<T> so it can wrap other stream, and since most of the operations return Stream<T>, the calls can be easily chained with each other, for example:

const numbers: Array<number> = ...
const evenSquares = new Stream(numbers)
   .filter(v => v % 2 == 0)
   .map(v => v * v)
   .toArray();

Types can be primitives (as in the example above) but can also be Objects, so SQL-like instructions can be used:

const users: Array<{name: string, age: number, city: string}> = ...
const usersByCity = new Stream(users)
  .where("age", ">=", 25)
  .groupBy("city")
  .toArray();

Type parameters

T

Type of elements in the stream. Can be any type including Object, primitives, Iterable etc.

Summary of operations

FP-style

  • filter
  • map
  • reduce
  • flat
  • flatMap

SQL-style

  • groupBy
  • join
  • select
  • where

Collectors

  • forEach
  • toArray
  • toMap

Shortcuts

  • last
  • max
  • min

Constructors

constructor

+ new Stream(iterableOrIteratorFactory: Iterable‹T› | function): Stream

Defined in index.ts:149

Creates a new instance of Stream by wrapping existing Iterable<T> or just a function that returns Iterator<T> (so generator function can be passed as well). For example:

// from Iterable<T>
const fromIterable = new Stream([1,2,3,4]);

// from () => Iterator<T>
function* generator() {
  yield 1;
  yield 2;
  yield 3;
}
const fromGenerator = new Stream(generator);

Parameters:

NameTypeDescription
iterableOrIteratorFactoryIterable‹T› | functioninstance of Iterable<T> or () => Iterator<T>

Returns: Stream

Methods

Symbol.iterator

Symbol.iterator(): Iterator‹T›

Defined in index.ts:179

Returns: Iterator‹T›


filter

filter(predicate: function): Stream‹T›

Defined in index.ts:210

Filters elements given a predicate function. Example of usage:

const evens = new Stream([1, 2, 3])
  .filter(i => i % 2 == 0)
  .toArray();

expect(even).toStrictEqual([2]);

Parameters:

predicate: function

function that accepts element and return true or false

▸ (t: T): boolean

Parameters:

NameType
tT

Returns: Stream‹T›


flat

flat(this: Stream‹Iterable‹any››): Stream‹T extends Iterable ? E : never›

Defined in index.ts:238

Flattens elements of this Stream<Iterable<T>> into Stream<T>. Example of usage:

const flattened = new Stream([[1,3], [2,4]])
   .flat()
   .toArray();

expect(flattened).toStrictEqual([1, 3, 2, 4]);

Parameters:

NameType
thisStream‹Iterable‹any››

Returns: Stream‹T extends Iterable ? E : never›


flatMap

flatMap<K>(field: K): Stream‹Val<T, K> extends Iterable ? E : never›

Defined in index.ts:259

First maps elements of Stream<T> to Stream<Iterable<R>> and then flattens into Stream<R>. For example:

const flattened = new Stream([{numbers: [1, 3]}, {numbers: [2, 4]}])
  .flatMap("numbers") 
  .toArray();
// "numbers" - name of a field that contains Iterable

expect(flattened).toStrictEqual([1, 3, 2, 4]);

Type parameters:

K: FieldOrFn‹T›

Parameters:

NameTypeDescription
fieldKfield extractor see FieldOrFn<T>

Returns: Stream‹Val<T, K> extends Iterable ? E : never›


forEach

forEach(fn: Fn‹T›): void

Defined in index.ts:562

Fetches all elements from the stream and executes given function for each element. Example of usage:

var sum = 0;
new Stream([1, 2, 3])
  .forEach(v => sum += v);

expect(sum).toStrictEqual(6);

Parameters:

NameTypeDescription
fnFn‹T›function to invoke

Returns: void


groupBy

groupBy<K>(keyFieldOrFn?: K): Stream‹object›

Defined in index.ts:516

Mimics SQL GROUP BY operator. Groups elements with the same given key. Keys must be in a sorted order, otherwise will raise an exception. Next element is emitted only once the element with the next key appears in the stream. Example of usage:

const ungrouped = [{a: 1, b: "val 1"}, {a: 1, b: "val 2"}, 
                   {a: 2, b: "val 3"}, {a: 2, b: "val 4"}];
const grouped = new Stream(ungrouped)
  .groupBy("a")
  .toArray();

expect(grouped).toStrictEqual([
  {key: 1, values: [{a: 1, b: "val 1"}, {a: 1, b: "val 2"}]},
  {key: 2, values: [{a: 2, b: "val 3"}, {a: 2, b: "val 4"}]}
]);

Type parameters:

K: FieldOrFn‹T›

Parameters:

NameTypeDescription
keyFieldOrFn?K

Returns: Stream‹object›


join

join<O, KC, KL, KR, JT>(other: Iterable‹O›, params: object): Stream‹JoinEntry‹T, O, JT››

Defined in index.ts:369

Mimics SQL JOIN operator. Depending on type of join, for each element of source stream lookups a corresponding element from joined stream, using join parameter that can either be a field, or a function.

If using SORTED join type, it will ensure that keys from both set come in the specified order, otherwise will raise an exception. This is the most intended usage of this operation as it won't need to pre-fetch all elements from second stream in memory. The output keys order is preserved, i.e. if join order is ascending, then join entries will be emitted with the keys being in ascending order.

If using UNSORTED join type, it will pre-fetch all elements from second stream into a hash map before any join entries can be emitted.

Keys are not required to be unique, for duplicate keys, join entries will be multiplied, like it happens in SQL:

[1,2,2] left join [2,2,3] = [{1,null}, {2,2}, {2,2}, {2,2}, {2,2}]

Example of usage:

let collectionA = [{a: 1, b: "val 1",}, {a: 2, b: "val 2",}, {a: 3, b: "val 3",}];
let collectionB = [{a: 1, b: "val a",}, {a: 2, b: "val b",}];
const joined = new Stream(collectionA)
  .join(collectionB, {joinType: JoinType.INNER_ASC, commonKey: "a"})
  .toArray();

expect(result).toStrictEqual([
  {key: 1, left: {a: 1, b: "val 1"}, right: {a: 1, b: "val a"}},
  {key: 2, left: {a: 2, b: "val 2"}, right: {a: 2, b: "val b"}}
]);

Type parameters:

O - type of elements in the other stream being joined

Parameters:

other: Iterable‹O› - other stream to join (right-side)

params: Optional object= {joinType?, commonKey?, leftKey?, rightKey?}

NameTypeDescription
commonKey?FieldOrFn‹T | O›Common field that belongs to both streams elements, or a function that can extract key from T | O; if provided, next 2 will be ignored.
leftKey?FieldOrFn‹O›Field that belongs to current (left) stream elements, or a function that can extract key from T. If not provided, then elements will be used as keys and are supposed to be primitive.
rightKey?JoinTypeField that belongs to other (right) stream elements, or a function that can extract key from O. If not provided, then elements will be used as keys and are supposed to be primitive.
joinType?FieldOrFn‹T›Join mode, default value is JoinType.INNER_ASC.

JoinType is defining a semantic of a join operation as follows:

JoinTypeLeftRightResult
INNER_ASC[1,2][2,3][{key: 2, left: 2, right: 2}]
LEFT_ASC[1,2][2,3][{key: 1, left: 2, right: null}, {key: 2, left: 2, right: 2}]
RIGHT_ASC[1,2][2,3][{key: 2, left: 2, right: 2}, {key: 3, left: null, right: 3}]
FULL_ASC[1,2][2,3][{key: 1, left: 1, right: null}, {key: 2, left: 2, right: 2}, {key: 3, left: null, right: 3}]
INNER_DESC[2,1][3,2][{key: 2, left: 2, right: 2}]
LEFT_DESC[2,1][3,2][{key: 2, left: 2, right: 2}, {key: 1, left: 2, right: null}]
RIGHT_DESC[2,1][3,2][{key: 3, left: 3, right: null}, {key: 2, left: 2, right: 2}]
FULL_DESC[2,1][3,2][{key: 3, left: 3, right: null}, {key: 2, left: 2, right: 2}, {key: 1, left: 2, right: null}]
INNER_UNSORTED[1,3,2][2,1,4][{key: 1, left: 2, right: 1}, {key: 2, left: 2, right: 2}]
LEFT_UNSORTED[1,3,2][2,1,4][{key: 1, left: 2, right: 1}, {key: 3, left: null, right: 3}, {key: 2, left: 2, right: 2}]

Returns: Stream‹JoinEntry‹T, O, JT››


last

last(): T

Defined in index.ts:638

Fetches all elements from the stream and returns the last element. Example of usage:

const result = new Stream([1, 2, 3]).last();
expect(result).toStrictEqual(3);

Returns: T


map

map<R>(mapFn: function): Stream‹R›

Defined in index.ts:225

Maps each element of a current stream with a mapper function and returns new Stream of newly created elements. Example of usage:

const squares = new Stream([1, 2, 3])
  .map(i => i * i)
  .toArray();

Type parameters:

R

Parameters:

mapFn: function

function that accepts current element and returns a new one. The function can optionally accept prev element (original and mapped one).

▸ (t: T, prevT?: T, prevR?: R): R

Parameters:

NameType
tT
prevT?T
prevR?R

Returns: Stream‹R›


max

max(this: Stream‹number›): number

Defined in index.ts:664

Fetches all elements from the stream and returns the maximal one. Example of usage:

const result = new Stream([1, 2, 3]).max();
expect(result).toStrictEqual(3);

Currently only supports numeric streams, proper comparator support to be added soon.

Parameters:

NameType
thisStream‹number›

Returns: number


min

min(this: Stream‹number›): number

Defined in index.ts:651

Fetches all elements from the stream and returns the minimal one. Example of usage:

const result = new Stream([1, 2, 3]).min();
expect(result).toStrictEqual(1);

Currently only supports numeric streams, proper comparator support be added soon.

Parameters:

NameType
thisStream‹number›

Returns: number


reduce

reduce<R>(reduceFn: function): R

Defined in index.ts:618

Fetches all elements from the stream and recursively applies reduceFn to each element providing previous result to each call. Example of usage:

const result = new Stream([1, 2, 3])
 .reduce<number>((a, b) => (a === undefined ? 0 : a) + b);

expect(result).toStrictEqual(6);

Type parameters:

R

Parameters:

reduceFn: function

function(accumulator: R | undefined, current: T, index: number) => R

▸ (accumulator: R | undefined, current: T, index: number): R

Parameters:

NameType
accumulatorR | undefined
currentT
indexnumber

Returns: R


select

select<U1, U2>(field1: U1, ...field2: U2[]): Stream‹U2 extends never ? TU1 : object›

Defined in index.ts:283

Mimics SQL SELECT operator, by restricting set of fields that need be returned. Accepts list of field names, and returns objects with only those fields, for example:

const selectedAB = stream([{a: 1, b: "str", c: 3}]).select("a", "b");
const selectedA = stream([{a: 1, b: "str", c: 3}]).select("a");

expect(selectedAB).toStrictEqual([{a: 1, b: "str"}]);
expect(selectedA).toStrictEqual([1]);

Type parameters:

U1: Field‹T›

U2: Field‹T›

Parameters:

NameTypeDescription
field1U1field name
...field2U2[]field name (none or many)

Returns: Stream‹U2 extends never ? TU1 : object›


toArray

toArray(): Array‹T›

Defined in index.ts:571

Fetches all elements from the stream and collect them int Array<T>.

Returns: Array‹T›


toMap

toMap<K, V>(key: K, val?: V): Map‹Val‹T, K›, Val‹T, V››

Defined in index.ts:594

Fetches all elements from the stream and collect them int Map<K, V>. Example of usage:

const result = new Stream([1, 2, 3])
  .toMap(t => `${t}`);

expect(result).toStrictEqual(new Map([['1', 1], ['2', 2], ['3', 3]]));

Type parameters:

K: FieldOrFn‹T›

V: FieldOrFn‹T›

Parameters:

NameTypeDescription
keyKkey field or function
val?Vvalue field or function

Returns: Map‹Val‹T, K›, Val‹T, V››


where

where<K>(field: K, compareOp: ComparisonOp, value: Val‹T, K›): Stream‹T›

Defined in index.ts:314

Mimics SQL WHERE clause, by including only the records that satisfy given parameters. Example of usages:

const objs = [{a: 1, b: "val a", c: 3}, {a: 2, b: "val b", c: 4}, 
              {a: 3, b: "val c", c: 4}];
const result = new Stream(objs)
  .where("a", "<", 3)
  .where("b", "!=", "val a")
  .toArray();

expect(result).toStrictEqual([{a: 2, b: "val b", c: 4}]);

Type parameters:

K: FieldOrFn‹T›

Parameters:

NameTypeDescription
fieldKfield name, see Field<T>
compareOpComparisonOpcomparison operation, see ComparisonOp
valueVal‹T, K›value of type T[Field] to compare with

Returns: Stream‹T›

Creating streams from existing collections

from

from<T>(first: Iterable‹T›, second: Iterable‹T›, ...rest: Iterable‹T›[]): Stream‹T[]›

Defined in index.ts:21

Cross-multiplies multiple Iterable's of the same type T into Stream<T[]>. Can accept any number of args. This function can be used as a shortcut - from(someIterable) instead of new Stream(someIterable).

Example of usage:

const result = from([1, 3], [2, 4])
  .toArray();

expect(result).toStrictEqual([[1, 3], [1, 4], [2, 3], [2, 4]]);

Type parameters:

T

Parameters:

NameTypeDescription
firstIterable‹T›(required) first Iterable
secondIterable‹T›(optional) second Iterable
...restIterable‹T›[](optional) other Iterables

Returns: Stream‹T[]›


range

range(from: number, to: number): Stream‹number›

Defined in index.ts:60

Creates a Stream<number> with all numbers from the range. Example of usage:

const result = range(0, 10)
  .toArray();

expect(result).toStrictEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);

Parameters:

NameTypeDescription
fromnumberstart of range (inclusive)
tonumberend of range (inclusive)

Returns: Stream‹number›


0.5.7

4 years ago

0.5.6

4 years ago

0.5.5

4 years ago

0.5.4

4 years ago

0.5.3

4 years ago

0.5.2

4 years ago

0.5.1

4 years ago

0.5.0

4 years ago