Data sequences
This API allows working with data sequences of different kinds in a functional style, e.g. map/reduce.
Instances of the util.data.Sequence
class can be created from iterable input, either an in-memory structure or a stream of data, e.g. read from a network socket. The Sequence class provides intermediate (work on single elements, return a new Sequence) and terminal (consume all elements, returning a single value) operations.
use util\data\{Sequence, Collectors, Aggregations};
$return= Sequence::of([1, 2, 3, 4])
->filter(fn($e) => 0 === $e % 2)
->toArray()
;
// $return= [2, 4]
$return= Sequence::of([1, 2, 3, 4])
->map(fn($e) => $e * 2)
->toArray()
;
// $return= [2, 4, 6, 8]
$i= 0;
$return= Sequence::of([1, 2, 3, 4])
->counting($i)
->reduce(0, fn($a, $b) => $a + $b)
;
// $i= 4, $return= 10
$names= Sequence::of($this->people)
->map('com.example.Person::name')
->collect(Collectors::joining(', '))
;
// $names= "Timm, Alex, Dude"
$experience= Sequence::of($this->employees)
->collect(Collectors::groupingBy(
fn($e) => $e->department(),
Aggregations::average(fn($e) => $e->years())
))
;
// $experience= util.collections.HashTable[2] {
// Department("A") => 12.8
// Department("B") => 3.5
// }
Instances of the util.data.Optional
class are thin wrappers around possible NULL values. The operations provided by Optional class help in reducing conditional code:
use util\data\Optional;
$first= Optional::of($repository->find($user));
if ($first->present()) {
$user= $first->get(); // When Repository::find() returned non-null
}
$user= $first->orElse($this->currentUser);
$user= $first->orUse(fn() => $this->currentUser());
$name= $first
->filter(fn($user) => $user->isActive())
->whenAbsent($this->currentUser)
->whenAbsent(fn() => $this->guestUser())
->map('com.example.User::name')
->get()
;
Sequences can be created from a variety of sources, and by using these static methods:
lang.types.ArrayList
and lang.types.ArrayMap
as well as anything from util.collections
, util.XPIterator
instances, PHP iterators and iterator aggregates, PHP 5.5 generators (yield), as well as sequences themselves. Passing NULL will yield an empty sequence.limit()
!limit()
!The following operations return a new Sequence
instance on which more intermediate or terminal operations can be invoked:
skip(4)
skips the first four elements, skip(function($e) { return 'initial' === $e; })
will skip all elements which equal to the string initial. limit(10)
stops iteration once ten elements have been returned, limit(function($e) { return 'stop' === $e; })
will stop once the first element equal to the string stop is encountered.util.Filter
instance.peek('var_dump', [])
.util.data.ICollector
instance. Unlike the terminal operation below, passes the elements on.util.Objects::hashOf()
method by default (but can be passed another function).util.Comparator
instance or the sort flags from PHP’s sort() function (e.g. SORT_NUMERIC | SORT_DESC
).The following operations return a single value by consuming all of the sequence:
util.data.Optional
instance. A value will be present if the sequence was not empty.first()
, but raises an exception if more than one element is contained in the sequence.util.Comparator
instance.min()
, but returns the largest element instead.util.data.ICollector
instance.To use controlled iteration on a sequence, you can use the foreach
statement or receive a “hasNext/next”-iterator via the iterator()
accessor. If the sequence is based on seekable data (rule of thumb: all in-memory structures will be seekable), these operations can be repeated with the same effect. Otherwise, a util.data.CannotReset
exception will be raised (e.g., for data streamed from a socket).