PHPackages                             stubbles/sequence - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. stubbles/sequence

ActiveLibrary

stubbles/sequence
=================

Stream your iterators.

v11.0.0(5mo ago)314.9k[1 PRs](https://github.com/stubbles/stubbles-sequence/pulls)5BSD-3-ClausePHPPHP ^8.3CI passing

Since Jan 11Pushed 1mo ago2 watchersCompare

[ Source](https://github.com/stubbles/stubbles-sequence)[ Packagist](https://packagist.org/packages/stubbles/sequence)[ Docs](http://stubbles.net/)[ RSS](/packages/stubbles-sequence/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (7)Dependencies (3)Versions (8)Used By (5)

stubbles/sequence
=================

[](#stubblessequence)

Stream your iterators.

Build status
------------

[](#build-status)

[![Tests](https://github.com/stubbles/stubbles-sequence/workflows/Tests/badge.svg)](https://github.com/stubbles/stubbles-sequence/workflows/Tests/badge.svg)

[![Latest Stable Version](https://camo.githubusercontent.com/30a17c9353c8071ced3616e4fb6434efee926f2f8c3b1897a55972dce3c0647d/68747470733a2f2f706f7365722e707567782e6f72672f73747562626c65732f73657175656e63652f76657273696f6e2e706e67)](https://packagist.org/packages/stubbles/sequence) [![Latest Unstable Version](https://camo.githubusercontent.com/eb338de713d6fa26ba0f280e77545d33aae8b822085e5ab8dda5a0474b6f04f0/68747470733a2f2f706f7365722e707567782e6f72672f73747562626c65732f73657175656e63652f762f756e737461626c652e706e67)](//packagist.org/packages/stubbles/sequence)

Installation
------------

[](#installation)

*stubbles/sequence* is distributed as [Composer](https://getcomposer.org/)package. To install it as a dependency of your package use the following command:

```
composer require "stubbles/sequence": "^11.0"

```

Requirements
------------

[](#requirements)

*stubbles/sequence* requires at least PHP 8.3.

Introduction
------------

[](#introduction)

Sequence operations are divided into intermediate and terminal operations, and are combined to form pipelines. A pipeline consists of a source (such as a collection, an array, a generator function, or an I/O channel); followed by zero or more intermediate operations such as `Sequence::filter()` or `Sequence::map()`; and a terminal operation such as `Sequence::each()` or `Sequence::reduce()`.

Intermediate operations return a new Sequence. They are always lazy; executing an intermediate operation such as `Sequence::filter()` does not actually perform any filtering, but instead creates a new Sequence that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal operation of the pipeline is executed.

Terminal operations, such as `Sequence::each()` or `Sequence::reduce()`, may traverse the Sequence to produce a result or a side-effect. After the terminal operation is performed, the pipeline is considered consumed, and can no longer be used; if you need to traverse the same data source again, you must return to the data source to get a new Sequence. In almost all cases, terminal operations are eager, completing their traversal of the data source and processing of the pipeline before returning. Only the terminal operation `Sequence::getIterator()` is not; this is provided as an "escape hatch" to enable arbitrary client-controlled pipeline traversals in the event that the existing operations are not sufficient to the task.

Create a sequence
-----------------

[](#create-a-sequence)

### `Sequence::of($elements)`

[](#sequenceofelements)

Creates sequence of given `$elements` which can be either a `\Traversable` or an array.

Since release 8.1 it is possible to create a sequence in these ways:

- no arguments: equivalent to `Sequence::of([])`
- one argument which is an instance of `Sequence`: returns exactly this sequence
- one argument which is an `array` or a `\Traversable`: sequence of this
- one argument which is none of the above: equivalent to `Sequence::of([$element])`
- two or more arguments: sequence of the list of arguments

### `Sequence::infinite($seed, callable $operation)`

[](#sequenceinfiniteseed-callable-operation)

Creates an infinite sequence. With `$seed` the initial value can be specified, while `$operation` must be callable which takes the current value and generates the next value.

Warning: calling terminal operations on an infinite sequence result in endless loops trying to calculate the terminal value. Before calling a terminal operation the sequence should be limited via `Sequence::limit()`. Alternatively you can iterate over the sequence itself and stop the iteration when required.

### `Sequence::generate($seed, callable $operation, callable $validator)`

[](#sequencegenerateseed-callable-operation-callable-validator)

Creates a sequence which generates values while being worked on.

The sequence ends when the provided validator returns `false` for the first time. The validator receives two values: the last generated value, and the amount of values already generated.

The following example generates an array which has $start as first value, where each following value is incremented by 2, and the amount of values in the array is either maximal 100 or PHP\_INT\_MAX has been reached:

```
Sequence::generate(
     $start,
     function($previous) { return $previous + 2; },
     function($value, $invocations) { return $value < (PHP_INT_MAX - 1) &&  100 >= $invocations; }
)->values();
```

Intermediate operations
-----------------------

[](#intermediate-operations)

### `limit($n)`

[](#limitn)

Limits sequence to the first n elements, i.e. stops iteration when the nth element is reached.

```
Sequence::of([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])->limit(3)->data();
```

Result: `[1, 2, 3]`

### `skip($n)`

[](#skipn)

Skips the first n elements of the sequence.

```
Sequence::of([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])->skip(10)->data();
```

Result: `[11]`

### `filter(callable $predicate)`

[](#filtercallable-predicate)

Returns a new sequence with elements matching the given predicate. The given predicate reveives a value and must return true to accept the value or false to reject the value.

```
Sequence::of([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
        ->filter(function($value) { return $value % 2 === 0;})
        ->data();
```

Result: `[2, 4, 6, 8, 10]`

### `map(callable $valueMapper, callable $keyMapper = null)`

[](#mapcallable-valuemapper-callable-keymapper--null)

Returns a new sequence which maps each element using the given mapper.

```
Sequence::of([1, 2, 3, 4])->map(function($e) { return $e * 2; })->data();
```

Result: `[2, 4, 6, 8]`

### `mapKeys(callable $keyMapper)`

[](#mapkeyscallable-keymapper)

Returns a new sequence which maps each key using the given mapper.

```
Sequence::of([1, 2, 3, 4])->mapKeys(function($e) { return $e * 2; })->data();
```

Result: `[0 => 1, 2 => 2, 4 => 3, 6 => 4]`

### `append($other)`

[](#appendother)

Appends any value, creating a new combined sequence.

In case given $other is not something iterable it is simply appended as last element to a new sequence.

```
Sequence::of([1, 2])->append([3, 4]); // results in new sequence with [1, 2, 3, 4]
```

### `peek(callable $valueConsumer, callable $keyConsumer = null)`

[](#peekcallable-valueconsumer-callable-keyconsumer--null)

Allows consumer to receive the value before any further operations are applied.

You can use it to inspect the values and keys before any further operations are applied. This is especially useful when you need to debug the contents of a sequence.

```
Sequence::of([1, 2, 3, 4])->peek('var_dump');
```

Terminal operations
-------------------

[](#terminal-operations)

### `each(callable $consumer)`

[](#eachcallable-consumer)

Invokes consumer for each element and returns the amount of invocations.

The consumer receives the element as first value, and the key as second:

```
Sequence::of(['foo' => 'bar'])->each(
        function($element, $key)
        {
            // do something with $element and $key
        }
);
```

The key is optional and can be left away:

```
Sequence::of(['foo' => 'bar'])->each(
        function($element)
        {
            // do something with $element and $key
        }
);
```

Iteration can be stopped by returning `false` from the consumer. The following example stops when it reaches element 2:

```
Sequence::of([1, 2, 3, 4])->each(
        function($element)
        {
            echo $element . "\n";
            return (2 first(); // displays 'foo'
```

### `reduce(callable $accumulate = null, $identity = null)`

[](#reducecallable-accumulate--null-identity--null)

Reduces all elements of the sequence to a single value. The given callable will receive two values: the current reduced value which on first invocation is the value of `$identity`, and the current element as second. It needs to calculate and return a new value from both which becomes the new value of identity, and will be returned from `reduce()` after the last element has been processed.

```
Sequence::of([1, 2, 3, 4])->reduce(function($identity, $b) { return $identity + $b; });
```

In case no callable is provided an instance of `stubbles\sequence\Reducer` will be returned which provides convenience methods for some common reduction operations.

#### `reduce()->toSum(callable $summer = null)`

[](#reduce-tosumcallable-summer--null)

Reduces sequence to the sum of all elements. By default assumes the sequence consists of numbers and simply adds them one after another.

```
Sequence::of([1, 2, 3, 4])->reduce()->toSum();
```

In case the sequence consists of other types a callable can be passed that can calculate the sum instead. The callable must expect two values: the sum calculated until now and a single element. The return value must be the new sum with the given element.

```
Sequence::of(['a', 'b', 'c', 'd'])->reduce()->toSum(
        function($sum, $element)
        {
            return $sum + ord($element);
        }
);
```

#### `reduce()->toMin(callable $min = null)`

[](#reduce-tomincallable-min--null)

Reduces sequence to the smallest element. By default assumes the sequence consists of numbers.

```
Sequence::of([1, 2, 3, 4])->reduce()->toMin();
```

In case the sequence consists of other types a callable can be passed that can calculate the smallest value instead. The callable must expect two values: the smalles value found until until now (which `null` on the first invocation) and a single element. The return value must be the smaller of both arguments.

```
Sequence::of(['a', 'b', 'c', 'd'])->reduce()->toSum(
        function($smallest, $element)
        {
            return (null === $smallest || ord($element) < ord($smallest)) ? $element : $smallest;
        }
);
```

#### `reduce()->toMax(callable $max = null)`

[](#reduce-tomaxcallable-max--null)

Reduces sequence to the greatest element. By default assumes the sequence consists of numbers.

```
Sequence::of([1, 2, 3, 4])->reduce()->toMax();
```

In case the sequence consists of other types a callable can be passed that can calculate the greatest value instead. The callable must expect two values: the greatest value found until until now (which `null` on the first invocation) and a single element. The return value must be the greater of both arguments.

```
Sequence::of(['a', 'b', 'c', 'd'])->reduce()->toMax(
        function($greatest, $element)
        {
            return (null === $greatest || ord($element) > ord($greatest)) ? $element : $greatest;
        }
);
```

### `collect(Collector $collector = null)`

[](#collectcollector-collector--null)

Collects all elements into a structure defined by given collector.

A collector accumulates elements into a structure, optionally transforming the result into a final representation.

In case no collector is provided an instance of `stubbles\sequence\Collectors`will be returned which provides convenience methods for some common collector operations.

#### `collect()->inList()`

[](#collect-inlist)

Returns the values of the sequence as array.

```
Sequence::of(['foo' => 'bar', 'dummy' => 'baz'])->collect()->inList(); // returns ['bar', 'baz']
```

#### `collect()->inMap(callable $selectKey = null, callable $selectValue = null)`

[](#collect-inmapcallable-selectkey--null-callable-selectvalue--null)

Returns the sequence data with keys and values as associative array. The `$selectKey` callable will be used to determine the key for a value in the new map, and `$selectValue` will be used to determine the value. If they are omitted the key and value from the source elements will be used as they are.

```
$people= [
        1549 => new Employee(1549, 'Timm', 'B', 15),
        1552 => new Employee(1552, 'Alex', 'I', 14),
        6100 => new Employee(6100, 'Dude', 'I', 4)
];
$employees = Sequence::of($people)->collect()->inMap(
        function(Employee $e) { return $e->id(); },
        function(Employee $e) { return $e->name(); }
); // results in [1549 => 'Timm', 1552 => 'Alex', 6100 => 'Dude']
```

#### `collect()->inPartitions(callable $predicate, Collector $base = null)`

[](#collect-inpartitionscallable-predicate-collector-base--null)

Groups the elements in two partitions according to given predicate.

```
$timm = new Employee(1549, 'Timm', 'B', 15);
$alex = new Employee(1552, 'Alex', 'I', 14);
$dude = new Employee(6100, 'Dude', 'I', 4);
$employees = Sequence::of([$timm, $alex, $dude])->collect()->inPartitions(
        function(Employee $e) { return $e->years() > 10; }
);  // results in [true  => [$timm, $alex], false => [$dude]]
```

The second argument can be used to influence the actual partition value.

```
$timm = new Employee(1549, 'Timm', 'B', 15);
$alex = new Employee(1552, 'Alex', 'I', 14);
$dude = new Employee(6100, 'Dude', 'I', 4);
$employees = Sequence::of([$timm, $alex, $dude])->collect()->inPartitions(
        function(Employee $e) { return $e->years() > 10; },
        Collector::forAverage(function(Employee $e) { return $e->years(); })
);  // results in [true  => 14.5, false => 4]
```

#### `collect()->inGroups(callable $classifier, Collector $base = null)`

[](#collect-ingroupscallable-classifier-collector-base--null)

Groups the elements in two partitions according to given predicate.

```
$timm = new Employee(1549, 'Timm', 'B', 15);
$alex = new Employee(1552, 'Alex', 'I', 14);
$dude = new Employee(6100, 'Dude', 'I', 4);
$employees = Sequence::of([$timm, $alex, $dude])->collect()->inGroups(
        function(Employee $e) { return $e->department(); }
); // results in ['B' => [$timm], 'I' => [$alex, $dude]]
```

The second argument can be used to influence the actual group value:

```
$timm = new Employee(1549, 'Timm', 'B', 15);
$alex = new Employee(1552, 'Alex', 'I', 14);
$dude = new Employee(6100, 'Dude', 'I', 4);
$employees = Sequence::of([$timm, $alex, $dude])->collect()->inGroups(
        function(Employee $e) { return $e->department(); },
        Collector::forSum(function(Employee $e) { return $e->years(); })
); // results in ['B' => 15, 'I' => 18]
```

#### `collect()->byJoining($delimiter = ', ', $prefix = '', $suffix = '', $keySeparator = null)`

[](#collect-byjoiningdelimiter----prefix---suffix---keyseparator--null)

Concatenates all elements into a single string.

```
$timm = new Employee(1549, 'Timm', 'B', 15);
$alex = new Employee(1552, 'Alex', 'I', 14);
$dude = new Employee(6100, 'Dude', 'I', 4);
$employees = Sequence::of([$timm, $alex, $dude])
        ->map(function(Employee $e) { return $e->name(); })
        ->collect()
        ->byJoining();
// results in 'Timm, Alex, Dude'
```

When `$keySeparator` is supplied the key will also be included:

```
$timm = new Employee(1549, 'Timm', 'B', 15);
$alex = new Employee(1552, 'Alex', 'I', 14);
$dude = new Employee(6100, 'Dude', 'I', 4);
$employees = Sequence::of([1549 => $timm, 1552 => $alex, 6100 => $dude])
        ->map(function(Employee $e) { return $e->name(); })
        ->collect()
        ->byJoining(', ', '(', ')', ':');
// results in '(1549:Timm, 1552:Alex, 6100:Dude)'
```

### `count()`

[](#count)

Returns number of elements in sequence.

```
echo Sequence::of(['foo', 'bar', 'baz'])->count(); // displays 3
```

As Sequence is also an instance of `\Countable` it can also be used with PHP's native `count()` function:

```
echo count(Sequence::of(['foo', 'bar', 'baz'])); // displays 3
```

### `values()`

[](#values)

Returns the values of the sequence as array, shortcut for `collect()->inList()`.

```
Sequence::of(['foo' => 'bar', 'dummy' => 'baz'])->values(); // returns ['bar', 'baz']
```

### `data()`

[](#data)

Returns the sequence data with keys and values as associative array. Shortcut for `collect()->inMap()`.

```
Sequence::of(['foo' => 'bar', 'dummy' => 'baz'])->data(); // returns ['foo' => 'bar', 'dummy' => 'baz']
```

Sequence validation with *bovigo/assert*
----------------------------------------

[](#sequence-validation-with-bovigoassert)

*Available since release 8.0.0*

In case you use [*bovigo/assert*](https://github.com/bovigo/assert) for assertions in your unit tests *stubbles/sequence* provides two predicates which can be used to ensure a sequence contains the expected data:

```
assertThat($yourSequence, Provides::values([1, 2, 3]));
assertThat($yourSequence, Provides::data(['foo' => 1, 'bar' => 2, 'baz' => 3]));
```

Both are available with the class `stubbles\sequence\assert\Provides`. While the first one checks values only and does not consider the keys, the second also checks the keys. Please note that both check exactly those elements - if the sequence contains more values the predicated will fail.

###  Health Score

57

—

FairBetter than 98% of packages

Maintenance88

Actively maintained with recent releases

Popularity26

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity83

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 75% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~601 days

Recently: every ~856 days

Total

7

Last Release

161d ago

Major Versions

v7.0.0 → v8.0.02016-07-11

v8.1.0 → v9.0.02019-10-29

v9.0.0 → v10.0.02022-12-26

v10.1.0 → v11.0.02025-11-29

PHP version history (6 changes)v7.0.0PHP &gt;=5.6.0

v8.0.0PHP ^7.0

v9.0.0PHP ^7.3

v10.0.0PHP ^8.0

v10.1.0PHP ^8.2

v11.0.0PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/cde3f4e0a0e4454942288eb300c91644bd359cc3572d65b473e3484701fa4931?d=identicon)[mikey179](/maintainers/mikey179)

---

Top Contributors

[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (51 commits)")[![mikey179](https://avatars.githubusercontent.com/u/190475?v=4)](https://github.com/mikey179 "mikey179 (17 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/stubbles-sequence/health.svg)

```
[![Health](https://phpackages.com/badges/stubbles-sequence/health.svg)](https://phpackages.com/packages/stubbles-sequence)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
