Stream.js is a lightweight dependency-free utility library for ECMAScript 5 compatible JavaScript engines, such as browsers, Node.js or the Java 8 Nashorn engine. No native JavaScript types are modified in any way. Instead Stream.js exposes a single function Stream
which serves as the constructor for creating and working with streams of in-memory data. It also serves as namespace for additional types such as Stream.Optional
.
Stream.js is a functional programming library and follows strict naming conventions to describe different kind of function arguments. Please keep in mind that all functions passed as stream operations must be stateless. That means those functions should not modify the internal state of the streams underlying data structure (e.g. add or remove elements from the input array). Stateful functions may result in non-deterministic or incorrect behavior.
Predicate functions accept a single element of the stream as the first argument and return a boolean.
var predicate = function(num) {
return num % 2 === 1;
}
Mapping functions accept a single element of the stream as the first argument and transform this argument into something else, returning another object.
var mappingFn = function(num) {
return {a: num};
}
Supplier functions return new objects out of nowhere. No arguments are passed.
var supplier = function() {
return Math.random();
}
Consumer functions accept a single element of the stream as the first argument and perform some custom actions, returning nothing.
var consumer = function (obj) {
console.log("consuming", obj);
}
Comparator functions accept two arguments and compare those arguments for order, returning 0, 1 or -1.
var defaultComparator = function (a, b) {
if (a === b) {
return 0;
}
return a > b ? 1 : -1;
};
Accumulator functions accept two arguments and return an object, e.g. by merging both arguments into a single result. Normally those functions are called multiple times for all elements of the stream, passing the last accumulator result as first argument and the current element of the stream as second argument.
var accumulator = function(result, obj) {
return result + " " + obj;
}
The following constructor functions can be used to create different kind of streams.
Returns a new stream for the given array.
Stream([1, 2, 3, 4, 5])
.filter(function(i) {
return i % 2 === 1;
})
.toArray(); // => 1, 3, 5
Alias: Stream.from
Returns a new stream for the given object hash by streaming upon the values of each key.
Stream({a: 1, b: 2, c: 3, d: 4, e: 5})
.filter(function(i) {
return i % 2 === 1;
})
.toArray(); // => 1, 3, 5
Alias: Stream.from
Returns a new stream for the given set.
// ES6 Set
var mySet = new Set([1, 2, 3, 4, 5]);
Stream(mySet)
.filter(function(i) {
return i % 2 === 1;
})
.toArray(); // => 1, 3, 5
Alias: Stream.from
Returns a new stream for the given map.
// ES6 Map
var myMap = new Map();
data.set("key1", 1);
data.set("key2", 2);
data.set("key3", 3);
data.set("key3", 4);
data.set("key3", 5);
Stream(myMap)
.filter(function(i) {
return i % 2 === 1;
})
.toArray(); // => 1, 3, 5
Alias: Stream.from
Returns a new stream for the given iterator. The iterator must conform to the Iterator Protocol.
// ES6 Generator
function* iterator() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
yield 6;
}
Stream(iterator())
.filter(function(i) {
return i % 2 === 1;
})
.toArray(); // => 1, 3, 5
Alias: Stream.from
Returns a new stream for the given string. The string will be splitted by characters.
var stream = Stream("ABCDEFG");
Alias: Stream.from
Returns a new stream for the given string. The string will be split by the separator
string.
var stream = Stream("a,b,c,d", ","); // creates a stream with 4 items
// creates a stream with 4 items - the trailing comma is not taken into account
stream = Stream("a,b,c,d,", ",");
Alias: Stream.from
Returns a new stream for the given arguments.
var stream = Stream.of(1, 2, 3, 4);
Returns a new empty stream.
var stream = Stream.empty();
Returns a new stream for the given number range.
var stream = Stream.range(0, 10); // => 0..9
Returns a new stream for the given number range.
var stream = Stream.rangeClosed(0, 9); // => 0..9
Returns a new infinite stream. The elements of the stream are generated by the given supplier function.
// generate random numbers between 1 and 10
var stream = Stream.generate(function() {
return Math.floor(Math.random() * 10) + 1;
});
Returns a new infinite stream. The elements of the stream are generated by utilizing the given iterator function, starting with seed
at n=0, then calling fn(seed) for n=1, fn(fn(seed)) for n=2 etc.
// 1, 2, 4, 8, 16, 32, ...
var stream = Stream.iterate(1, function (num) {
return num * 2;
});
Intermediate operations all return a stream, thus enabling you to chain multiple operations one after another without using semicolons.
Filters the elements of the stream to match the given predicate function and returns the stream.
Stream([1, 2, 3, 4, 5])
.filter(function (num) {
return num % 2 === 1; // => 1, 3, 5
});
Filters the elements of the stream to match the given regular expression and returns the stream.
// starts with a
Stream(["a1", "a2", "b1"])
.filter(/a.*/); // => a1, a2
Filters the elements of the stream to match the given sample object and returns the stream.
var data = [
{a: 1, b: 1},
{a: 2, b: 2},
{a: 1, b: 3}
];
Stream(data)
.filter({a: 1});
// => {a: 1, b: 1}, {a: 1, b: 3}
Filters (removes) the null
values of the stream. It performs a strongly typed check, so it keeps every other
falsy values.
Stream([1, null, false, NaN, undefined, 0, ""])
.filterNull()
// => 1, false, NaN, undefined, 0, ""
Filters (removes) the falsy values of the stream.
Stream([1, false, 2, null, NaN, undefined, 0, ""])
.filterFalsy()
// => 1, 2
Applies the given mapping function to each element of the stream and returns the stream.
Stream(numbers)
.map(function (num) {
return {a: num};
});
Maps each element of the stream by resolving the given string path
and returns the stream.
E.g. map('a.b.c')
is equivalent to map(function(obj) { return obj.a.b.c; })
.
Stream([{foo: {bar: 'foobar'}}, ...])
.map('foo.bar');
Applies the given mapping function to each element of the stream and flattens the results by replacing each element with the contents of the element in case of collections, then returns the stream.
Stream([{nums: [1, 2, 3], ...])
.flatMap(function(obj) {
return obj.nums;
});
Maps each element of the stream by resolving the given string path
and flattens the results by replacing each elemet with the contents of the element in case of collections, then returns the stream.
E.g. flatMap('a.b.c')
is equivalent to flatMap(function(obj) { return obj.a.b.c; })
.
Stream([{foo: {bar: [1, 2, 3]}}, ...])
.map('foo.bar');
Sorts the elements of the stream according to the natural order and returns the stream.
Alias: sort
Stream([7, 3, 3, 1])
.sorted(); // => 1, 3, 3, 7
Sorts the elements of the stream according to the given comparator and returns the stream.
Alias: sort
Stream([{foo: 'bar'}, ...])
.sorted(function(a, b) {
if (a.foo === b.foo) return 0;
if (a.foo < b.foo) return -1;
return 1;
});
Sorts the elements of the stream according to the given string path and returns the stream.
Alias: sort
var data = [{a: 4}, {a: 1}, {a: 3}, {a: 2}];
Stream(data)
.sorted("a");
// => {a: 1}, {a: 2}, {a: 3}, {a: 4}
Randomly reorder all elements of the stream.
Stream([1, 2, 3, 4])
.shuffle(); // => 4, 1, 3, 2
Reverse the order of each elements of the stream.
Stream([1, 2, 3, 4])
.reverse(); // => 4, 3, 2, 1
Returns the stream consisting of the distinct elements of this stream.
Stream([1, 1, 2, 3, 3, 4])
.distinct(); // => 1, 2, 3, 4
Truncates the elements of the stream to be no longer than maxSize
and returns the stream.
Stream([1, 2, 3, 4])
.limit(2); // => 1, 2
Discards the first n
elements and returns the stream.
Stream([1, 2, 3, 4])
.skip(2); // => 3, 4
Discards all elements except those between the zero-based indices begin
(included) and end
(excluded).
Stream([1, 2, 3, 4])
.slice(1, 3); // => 2, 3
Performs the consumer function for each element and returns the stream.
Stream([1, 2, 3, 4])
.peek(function (num) {
console.log(num);
});
Takes all elements of the stream as long as predicate
is true. All elements are rejected from the moment predicate
is false for the first time.
Stream([1, 2, 3, 2, 1])
.takeWhile(function (num) {
return num < 3;
})
.toArray(); // => 1, 2
Takes all elements of the stream as long as regexp
matches. All elements are rejected from the moment regexp
doesn't match for the first time.
Stream(["a1", "a2", "b3", "a4"])
.takeWhile(/a.*/)
.toArray(); // => a1, a2
Takes all elements of the stream as long as sample
matches. All elements are rejected from the moment sample
doesn't match for the first time.
var data = [
{a: 1, b: 1},
{a: 1, b: 2},
{a: 2, b: 3},
{a: 1, b: 4}
];
Stream(data)
.takeWhile({a: 1})
.toArray(); // => {a: 1, b: 1}, {a: 1, b: 2}
Rejects all elements of the stream as long as predicate
is true. All elements are accepted from the moment predicate
is false for the first time.
Stream([1, 2, 3, 2, 1])
.dropWhile(function (num) {
return num < 3;
})
.toArray(); // => 3, 2, 1
Rejects all elements of the stream as long as regexp
matches. All elements are accepted from the moment regexp
doesn't match for the first time.
Stream(["a1", "a2", "b3", "a4"])
.dropWhile(/a.*/)
.toArray(); // => b3, a4
Rejects all elements of the stream as long as sample
matches. All elements are accepted from the moment sample
doesn't match for the first time.
var data = [
{a: 1, b: 1},
{a: 1, b: 2},
{a: 2, b: 3},
{a: 1, b: 4}
];
Stream(data)
.dropWhile({a: 1})
.toArray(); // => {a: 2, b: 3}, {a: 1, b: 4}
Terminal operations return a result (or nothing), so each streaming pipeline consists of 0 to n intermediate operations followed by exactly one terminal operation.
Returns an array containing the elements of the stream.
Alias: toList
var result = Stream([1, 2, 3, 4, 5])
.filter(function (num) {
return num % 2 === 1;
})
.toArray(); // => [1, 3, 5]
Performs the consumer function for each element of the stream.
Alias: each
Stream([1, 2, 3, 4])
.forEach(function (num) {
console.log(num);
});
Returns an Optional
wrapping the first element of the stream or Optional.empty()
if the stream is empty.
Alias: findAny
Stream([1, 2, 3, 4])
.findFirst()
.ifPresent(function (first) {
console.log(first); // => 1
});
Returns an Optional
wrapping the minimum element of the stream (according the natural order) or Optional.empty()
if the stream is empty.
Stream([4, 1, 3, 2])
.min()
.ifPresent(function (min) {
console.log(min); // => 1
});
Returns an Optional
wrapping the minimum element of the stream (according the given comparator function) or Optional.empty()
if the stream is empty.
Stream([{a: 3}, {a: 1}, {a: 2}])
.min(function (obj1, obj2) {
if (obj1.a === obj2.a) return 0;
return obj1.a > obj2.a ? 1 : -1;
})
.ifPresent(function (min) {
console.log(min); // => {a: 1}
});
Returns an Optional
wrapping the minimum element of the stream (according the given string path) or Optional.empty()
if the stream is empty.
Stream([{a: 3}, {a: 1}, {a: 2}])
.min("a")
.ifPresent(function (min) {
console.log(min); // => {a: 1}
});
Returns an Optional
wrapping the maximum element of the stream (according the natural order) or Optional.empty()
if the stream is empty.
Stream([4, 1, 3, 2])
.max()
.ifPresent(function (min) {
console.log(min); // => 1
});
Returns an Optional
wrapping the maximum element of the stream (according the given comparator function) or Optional.empty()
if the stream is empty.
Stream([{a: 3}, {a: 1}, {a: 2}])
.max(function (obj1, obj2) {
if (obj1.a === obj2.a) return 0;
return obj1.a > obj2.a ? 1 : -1;
})
.ifPresent(function (min) {
console.log(min); // => {a: 3}
});
Returns an Optional
wrapping the maximum element of the stream (according the given string path) or Optional.empty()
if the stream is empty.
Stream([{a: 3}, {a: 1}, {a: 2}])
.min("a")
.ifPresent(function (min) {
console.log(min); // => {a: 3}
});
Returns the sum of all elements in this stream.
Stream([1, 2, 3, 4])
.sum(); // => 10
Returns the sum of all elements for the given path in this stream.
Stream([{a: 1}, {a: 2}, {a: 3}])
.sum("a"); // => 6
Returns an Optional
wrapping the arithmetic mean of all elements of this stream or Optional.empty()
if the stream is empty.
Alias: avg
Stream([1, 2, 3, 4])
.average()
.ifPresent(function (avg) {
console.log(avg); // => 2.5
});
Returns an Optional
wrapping the arithmetic mean of all elements of this stream or Optional.empty()
if the stream is empty, by resolving the given path for each element.
Alias: avg
Stream([{a: 1}, {a: 2}, {a: 3}, {a: 4}])
.average("a")
.ifPresent(function (avg) {
console.log(avg); // => 2.5
});
Returns the number of elements of the stream.
Alias: size
Stream([1, 2, 3, 4])
.count(); // => 4
Returns whether all elements of the stream match the given predicate function.
Stream([1, 2, 3, 4])
.allMatch(function (num) {
return num > 1; // => false
});
Returns whether all elements of the stream match the given sample object.
Stream([{a: 1}, {a: 2}])
.allMatch({a: 1}); // => false
Returns whether all elements of the stream match the given regexp pattern.
Stream(["a1", "a2", "b3"])
.allMatch(/a.*/); // => false
Returns whether any element of the stream matches the given predicate function.
Stream([1, 2, 3, 4])
.anyMatch(function (num) {
return num > 1; // => true
});
Returns whether any element of the stream match the given sample object.
Stream([{a: 1}, {a: 2}])
.anyMatch({a: 1}); // => true
Returns whether any element of the stream matches the given regexp pattern.
Stream(["a1", "a2", "b3"])
.anyMatch(/a.*/); // => true
Returns whether no element of the stream matches the given predicate function.
Stream([1, 2, 3, 4])
.noneMatch(function (num) {
return num > 1; // => false
});
Returns whether no element of the stream match the given sample object.
Stream([{a: 1}, {a: 2}])
.noneMatch({a: 1}); // => false
Returns whether no element of the stream matches the given regexp pattern.
Stream(["a1", "a2", "a3"])
.noneMatch(/b.*/); // => true
Performs a reduction operation using the provided identity
object as initial value and the accumulator function and returns the reduced value.
Stream([1, 2, 3, 4])
.reduce(1000, function (result, num) {
return result + num; // => 1010
});
Performs a reduction operation using the first element of the stream as as initial value and the accumulator function and returns the reduced value wrapped as Optional
.
Stream([1, 2, 3, 4])
.reduce(function (result, num) {
return result + num;
})
.ifPresent(function (result) {
console.log(result); // => 10
});
Performs a generalized reduction operation denoted by the given collector and returns the reduced value. A collector consists of a supplier function, an accumulator function and an optional finisher function.
Stream([1, 2, 3, 4])
.collect({
supplier: function () {
return "Data: ";
},
accumulator: function (val, num) {
return val + num + " ";
},
finisher: function (val) {
return val + "!";
}
});
// => Data: 1 2 3 4 !
Groups all elements of the stream by applying the given keyMapper function and returns an object map, assigning an array value for each key.
Alias: groupBy
Stream([{a: "foo", b: 1}, {a: "bar", b: 2}, {a: "bar", b: 3}])
.groupBy(function (obj) {
return obj.a;
});
// => { foo: [{a: "foo", b: 1}], bar: [{a: "bar", b: 2}, {a: "bar", b: 3}] }
Groups all elements of the stream by resolving the given string path
for each element of the stream and returns an object map, assigning an array value for each key.
Stream([{a: "foo", b: 1}, {a: "bar", b: 2}, {a: "bar", b: 3}])
.groupBy('a');
// => { foo: [{a: "foo", b: 1}], bar: [{a: "bar", b: 2}, {a: "bar", b: 3}] }
Alias: groupBy
Groups all elements of the stream by applying the given keyMapper function and returns an object map, assigning a single value for each key. Multiple values for the same key will be merged using the given merge function. The second argument mergeFunction
is not required. If no merge function is present and multiple values are found for the same key, an error is thrown.
Alias: indexBy
Stream([{a: "foo", b: 1}, {a: "bar", b: 2}])
.toMap(function (obj) {
return obj.a;
});
// => { foo: {a: "foo", b: 1}, bar: {a: "bar", b: 2} }
Groups all elements of the stream by resolving the given path
for each element of the stream and returns an object map, assigning a single value for each key. Multiple values for the same key will be merged using the given merge function. The second argument mergeFunction
is not required. If no merge function is present and multiple values are found for the same key, an error is thrown.
Alias: indexBy
Stream([{a: "foo", b: 1}, {a: "bar", b: 2}])
.toMap("a");
// => { foo: {a: "foo", b: 1}, bar: {a: "bar", b: 2} }
Groups all elements of the stream by the results of applying the given predicate to each element of the stream, returning an object with two keys true
and false
.
Alias: partitionBy
Stream([1, 2, 3, 4])
.partitionBy(function (num) {
return num % 2 === 0;
});
// => {"true": [2, 4], "false": [1, 3]}
Groups all elements of the stream by the results of matching the given sample object to each element of the stream, returning an object with two keys true
and false
.
Alias: partitionBy
var data = [
{a: 1, b: 1},
{a: 2, b: 1},
{a: 3, b: 5}
];
Stream(data)
.partitionBy({b: 1});
// => {"true": [{a: 1, b: 1}, {a: 2, b: 1}], "false": [{a: 3, b: 5}]}
Groups all elements of the stream by the results of testing the given regexp pattern to each element of the stream, returning an object with two keys true
and false
.
Alias: partitionBy
Stream(["a1", "a2", "b1"])
.partitionBy(/a.*/);
// => {"true": ["a1", "a2"], "false": ["b1"]}
Groups all elements of the stream by chunks of the given size, returning an array of arrays.
Alias: partitionBy
Stream([1, 2, 3, 4])
.partitionBy(2);
// => [[1, 2,], [3, 4]]
Joins all elements of the stream into a string.
Alias: join
Stream([1, 2, 3, 4])
.joining(); // => "1234"
Joins all elements of the stream into a string, using the given delimiter.
Alias: join
Stream([1, 2, 3, 4])
.joining("-"); // => "1-2-3-4"
Joins all elements of the stream into a string, using the following non-required options: options.delimiter
, options.prefix
, options.suffix
.
Alias: join
Stream([1, 2, 3, 4])
.joining({
prefix: "PREFIX_",
suffix: "_SUFFIX",
delimiter: ","
});
// => "PREFIX_1,2,3,4_SUFFIX"
Returns a StreamIterator
to traverse upon the elements described by this stream. StreamIterator
defines a single method next
, returning an object holding the next value
and a boolean flag done
indicating if the iterator has been finished.
var iterator = stream.iterator(), result;
while (true) {
result = iterator.next();
console.log(result.value);
if (result.done) {
break;
}
}
Wraps a single value which may be null
or undefined
.
Creates a new optional wrapper for the given non-null and non-undefined value.
Stream.Optional.of(1);
Creates a new optional wrapper for the given value. The value may be null or undefined.
Stream.Optional.ofNullable(null);
Creates a new empty optional wrapper (same as Optional.ofNullable(null)
).
Stream.Optional.empty();
If a value is present and value matches the given predicate function, returns this optional, otherwise return an empty optional.
var optional = Stream.Optional.of({a: 23})
.filter(function (obj) {
return obj.a % 2 === 0;
});
optional.isPresent(); // => false
If a value is present apply the given mapping function and wrap the resulting value with an optional.
var optional = Stream.Optional.of({a: 23})
.map(function (obj) {
return obj.a;
});
optional.get(); // => 23
If a value is present apply the given optional-returning mapping function, and return the optional result or empty.
var optional = Stream.Optional.of({a: 23})
.flatMap(function (obj) {
return Stream.Optional.of(obj.a);
});
optional.get(); // => 23
Check if a value is present.
var optional = Stream.Optional.of(23);
optional.isPresent(); // => true
Returns the value if a value is present, otherwise throws an error.
var optional = Stream.Optional.of(23);
optional.get(); // => 23
Invoke the given consumer function for the specified value if present.
Stream.Optional.of(23)
.ifPresent(function (num) {
console.log(num); // => 23
});
Returns the value if present, otherwise return the given other
value.
var optional = Stream.Optional.empty();
optional.orElse(3); // => 3
Returns the value if present, otherwise return the result of invoking the supplier function.
var optional = Stream.Optional.empty();
optional.orElseGet(function () {
return 1337;
});
Returns the value if present, otherwise throw the given error.
var optional = Stream.Optional.empty();
optional.orElseThrow("something went wrong");