1.0.10 • Published 6 years ago

@t0bst4r/stream v1.0.10

Weekly downloads
1
License
ISC
Repository
gitlab
Last release
6 years ago

@t0bst4r/stream

pipeline status coverage report

Add java-like high performance stream api to your application

Installation and Usage

Installation via npm

npm install @t0bst4r/stream

Usage

Import the package to your project files

import * from "@t0bst4r/stream";

or use single imports

import { Stream } from "@t0bst4r/stream/dist/stream";

import "@t0bst4r/stream/dist/add/map";
import "@t0bst4r/stream/dist/add/flatMap";
import "@t0bst4r/stream/dist/add/filter";

import { findFirst } from "@t0bst4r/stream/dist/collectors/findFirst";
import { toList } from "@t0bst4r/stream/dist/collectors/toList";
import { groupBy } from "@t0bst4r/stream/dist/collectors/groupBy";

Create a new stream of any Iterable and do your stuff (like Array)

To create a new stream use Stream.Of(yourIterable) or Array<T>.prototype.stream().

const simpleStream: Stream<number> = [ 1, 2, 3, 4, 5 ].stream();
// produces a stream of [ 1, 2, 3, 4, 5 ]

const myStream: Stream<string> = Stream.Of([ "hello", "world", "some", "values" ]);
// produces a stream of [ "hello", "world", "some", "values" ]

const mappedStream: Stream<number> = myStream.map(str => str.length);
// produces a stream of [ 5, 5, 4, 6 ]

const filteredStream: Stream<number> = mappedStream.filter(num => num != 4);
// produces a stream of [ 5, 5, 6 ]

const flatMappedStream: Stream<number> = filteredStream.flatMap(num => [num, num * 2, num * 3]);
// produces a stream of [ 5, 10, 15, 5, 10, 15, 6, 12, 18 ]

Collectors

Then just collect your items:

filteredStream.collect(toList());
// produces: [ 5, 5, 6 ]

mappedStream.collect(findFirst());
// produces: 5 (or undefined if the stream is empty)

myStream.collect(groupBy(item => item.length));
// Stream<T> produces a Map<TKey, T[]>:
//  - key: 5, items: [ "hello", "world" ]
//  - key: 4, items: [ "some" ]
//  - key: 6, items: [ "values" ]

myStream.collect(groupBy(item => item.length, item => item.toUpperCase() ));
// Stream<T> produces a Map<TKey, TValue[]>:
//  - key: 5, items: [ "HELLO", "WORLD" ]
//  - key: 4, items: [ "SOME" ]
//  - key: 6, items: [ "VALUES" ]

Collectors can be used for arrays or any other iterable, too.

You can create your own Collectors, too. Just implement the Collector<T, R> interface.

Iterable and Iterator

This Stream API uses ES6 Iterables and Iterators to process the data. A stream can be created on any iterable like arrays, other streams, or custom iterable implementations.

It also implements the Iterable interface itself so that you could iterate over any stream object:

const myStream: Stream<string> = [ "hello", "world", "some", "values" ].stream();
for (let str of myStream) {
  console.log(str);
}

Every collector gets its own iterable/iterator over the mapped/filtered data so that you can reuse every stream:

let myStream: Stream<number> = [ "hello", "world", "some", "values" ].stream()
  .map(str => str.length);

let firstItem: number = myStream.collect(findFirst()); // 5
let allItemsWithoutFour: number[] = myStream.filter(len => len != 4)
  .collect(toList()); // [ 5, 5, 4, 6 ]
myStream.forEach(len => console.log(len)) // "5" "5" "4" "6"

Implement custom stream functions / extend the stream API

You can simply add custom methods to the stream class by defining new methods:

import { Stream } from "@t0bst4r/stream";

declare module "@t0bst4r/stream" {
  interface Stream<T> {
    yourCustomMethod(...): Stream<T>;
  }
}

Stream.prototype.yourCustomMethod = function<T>(...): Stream<T> {
  // do your stuff.
  // create a new stream or just
  return this;
}

Feel free to create pull requests to help me improving this API

Differences to JavaScript Array functions

The JavaScript Array functions run immediately after adding the filter or map statements to the Array.

Methods of this Stream API will only be executed if there is a collector collecting the items.

For example if you just want the first element after filtering and mapping an Array all items will be mapped and filtered:

const myItem: number = [ "hello", "world", "some", "values" ]

  .map(str => str.length) // [ 5, 5, 4, 6 ]
  // mapping callback will be called for each item (4 times)

  .filter(len => len == 5) // [ 5, 5 ]
  // filter callback will be called for each item (4 times)

  [0]; // 5

With this Stream API the findFirst-Collector will only process the items until the first item matches.

const myItem: number = [ "hello", "world", "some", "values" ].stream()

  .map(str => str.length)
  // will be only called once (while collecting)

  .filter(len => len == 5)
  // will be only called once (while collecting)

  .collect(findFirst()) // 5

If you do this without the JavaScript Array methods and without this Stream API this could look like this:

function findFirstMappedAndFiltered<T, R>(items: T[], mapCallback: (item: T) => R, filterCallback: (item: R) => boolean): R | undefined {
  for(let item of items) {
    let mappedItem: R = mapCallback(item);
    if (filterCallback(mappedItem)) {
      return mappedItem;
    }
  }
  return undefined;
}
1.0.10

6 years ago

1.0.9

6 years ago

1.0.8

6 years ago

1.0.7

6 years ago

1.0.6

6 years ago

1.0.5

6 years ago

1.0.4

6 years ago

1.0.3

6 years ago

1.0.2

6 years ago

1.0.1

6 years ago

1.0.0

6 years ago