{"id":18550311,"url":"https://github.com/xp-forge/sequence","last_synced_at":"2025-08-21T16:25:16.550Z","repository":{"id":18029495,"uuid":"21066283","full_name":"xp-forge/sequence","owner":"xp-forge","description":"Data sequences","archived":false,"fork":false,"pushed_at":"2024-10-05T11:15:03.000Z","size":500,"stargazers_count":1,"open_issues_count":3,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-07-17T20:02:29.696Z","etag":null,"topics":["collect","filter","map","php","reduce","stream","xp-framework"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xp-forge.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-06-21T10:45:05.000Z","updated_at":"2024-10-05T11:15:07.000Z","dependencies_parsed_at":"2024-11-06T21:04:15.938Z","dependency_job_id":"ea540aee-22c2-43f0-a0a5-781e1955e2ad","html_url":"https://github.com/xp-forge/sequence","commit_stats":null,"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/xp-forge/sequence","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xp-forge%2Fsequence","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xp-forge%2Fsequence/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xp-forge%2Fsequence/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xp-forge%2Fsequence/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xp-forge","download_url":"https://codeload.github.com/xp-forge/sequence/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xp-forge%2Fsequence/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271382860,"owners_count":24750107,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-20T02:00:09.606Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["collect","filter","map","php","reduce","stream","xp-framework"],"created_at":"2024-11-06T21:04:11.271Z","updated_at":"2025-08-21T16:25:16.497Z","avatar_url":"https://github.com/xp-forge.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Data sequences\n==============\n\n[![Build status on GitHub](https://github.com/xp-forge/sequence/workflows/Tests/badge.svg)](https://github.com/xp-forge/sequence/actions)\n[![XP Framework Module](https://raw.githubusercontent.com/xp-framework/web/master/static/xp-framework-badge.png)](https://github.com/xp-framework/core)\n[![BSD Licence](https://raw.githubusercontent.com/xp-framework/web/master/static/licence-bsd.png)](https://github.com/xp-framework/core/blob/master/LICENCE.md)\n[![Requires PHP 7.0+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-7_0plus.svg)](http://php.net/)\n[![Supports PHP 8.0+](https://raw.githubusercontent.com/xp-framework/web/master/static/php-8_0plus.svg)](http://php.net/)\n[![Latest Stable Version](https://poser.pugx.org/xp-forge/sequence/version.svg)](https://packagist.org/packages/xp-forge/sequence)\n\nThis API allows working with data sequences of different kinds in a functional style, e.g. map/reduce.\n\nExamples\n--------\n### Sequence\nInstances 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.\n\n```php\nuse util\\data\\{Sequence, Collectors, Aggregations};\n\n$return= Sequence::of([1, 2, 3, 4])\n  -\u003efilter(fn($e) =\u003e 0 === $e % 2)\n  -\u003etoArray()\n;\n// $return= [2, 4]\n\n$return= Sequence::of([1, 2, 3, 4])\n  -\u003emap(fn($e) =\u003e $e * 2)\n  -\u003etoArray()\n;\n// $return= [2, 4, 6, 8]\n\n$i= 0;\n$return= Sequence::of([1, 2, 3, 4])\n  -\u003ecounting($i)\n  -\u003ereduce(0, fn($a, $b) =\u003e $a + $b)\n;\n// $i= 4, $return= 10\n\n$names= Sequence::of($this-\u003epeople)\n  -\u003emap('com.example.Person::name')\n  -\u003ecollect(Collectors::joining(', '))\n;\n// $names= \"Timm, Alex, Dude\"\n\n$experience= Sequence::of($this-\u003eemployees)\n  -\u003ecollect(Collectors::groupingBy(\n    fn($e) =\u003e $e-\u003edepartment(),\n    Aggregations::average(fn($e) =\u003e $e-\u003eyears())\n  ))\n;\n// $experience= util.collections.HashTable[2] {\n//   Department(\"A\") =\u003e 12.8\n//   Department(\"B\") =\u003e 3.5\n// }\n```\n\n### Optional\nInstances of the `util.data.Optional` class are thin wrappers around possible NULL values. The operations provided by Optional class help in reducing conditional code:\n\n```php\nuse util\\data\\Optional;\n\n$first= Optional::of($repository-\u003efind($user));\nif ($first-\u003epresent()) {\n  $user= $first-\u003eget();    // When Repository::find() returned non-null\n}\n\n$user= $first-\u003eorElse($this-\u003ecurrentUser);\n$user= $first-\u003eorUse(fn() =\u003e $this-\u003ecurrentUser());\n\n$name= $first\n  -\u003efilter(fn($user) =\u003e $user-\u003eisActive())\n  -\u003ewhenAbsent($this-\u003ecurrentUser)\n  -\u003ewhenAbsent(fn() =\u003e $this-\u003eguestUser())\n  -\u003emap('com.example.User::name')\n  -\u003eget()\n;\n```\n\nCreation operations\n-------------------\nSequences can be created from a variety of sources, and by using these static methods:\n\n* **of** - accepts PHP arrays (zero-based as well as associative), all traversable data structures including `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.\n* **iterate** - Iterates starting with a given seed, applying a unary operator on this value and passing the result to the next invocation, forever. Combine with `limit()`!\n* **generate** - Iterates forever, returning whatever the given supplier function returns. Combine with `limit()`!\n\nIntermediate operations\n-----------------------\nThe following operations return a new `Sequence` instance on which more intermediate or terminal operations can be invoked:\n\n* **skip** - Skips past elements in the beginning. Using `skip(4)` skips the first four elements, `skip(function($e) { return 'initial' === $e; })` will skip all elements which equal to the string *initial*. \n* **limit** - Stops iteration when limit is reached. Using `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.\n* **filter** - Filters the sequence by a given criterion. The new sequence will only contain values for which it returns true. Accepts a function or a `util.Filter` instance.\n* **map** - Maps each element in the sequence by applying a function on it and returning a new sequence with the return value of that function.\n* **peek** - Calls a function for each element in the sequence; especially useful for debugging, e.g. `peek('var_dump', [])`.\n* **counting** - Increments the integer given as its argument for each element in the sequence.\n* **collecting** - Collects elements in this sequence to a `util.data.ICollector` instance. Unlike the terminal operation below, passes the elements on.\n* **flatten** - Flattens sequences inside the sequence and returns a new list containing all values from all sequences.\n* **distinct** - Returns a new sequence which only consists of unique elements. Uniqueness is calculated using the `util.Objects::hashOf()` method by default (*but can be passed another function*).\n* **zip** - Combines values from this sequence with a given enumerable value, optionally using a given transformation function.\n* **sorted** - Returns a sorted collection. Can be invoked with a comparator function, a `util.Comparator` instance or the sort flags from PHP's sort() function (e.g. `SORT_NUMERIC | SORT_DESC`).\n* **chunked** - Returns a chunked stream with chunks not exceeding the given size. The last chunk may have a smaller size.\n* **windowed** - Returns a sliding window stream - a list of element ranges that you would see if you were looking at the collection through a sliding window of the given size.\n\nTerminal operations\n-------------------\nThe following operations return a single value by consuming all of the sequence:\n\n* **toArray** - will return a PHP array with zero-based keys\n* **toMap** - will return a PHP associative array\n* **first** - will return the first element as an `util.data.Optional` instance. A value will be present if the sequence was not empty.\n* **single** - like `first()`, but raises an exception if more than one element is contained in the sequence.\n* **count** - will return the number of elements in the sequence\n* **min** - returns the smalles element. Compares numbers by default but may be given a comparator function or a `util.Comparator` instance.\n* **max** - same as `min()`, but returns the largest element instead.\n* **each** - Applies a given function to each element in the sequence, and returns the number of elements. Can be invoked without a function to consume \"silently\".\n* **reduce** - Perform a reduction on the elements in this sequence.\n* **collect** - Pass all elements in this sequence to a `util.data.ICollector` instance.\n\nIteration\n---------\nTo 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).\n\nFurther reading\n---------------\n\n* The [java.util.stream package](http://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html) \n* [JDK8: Stream style](http://de.slideshare.net/SergeyKuksenko/jdk8-stream-style) - by Sergey Kuksenko, Performance Engineering at Oracle on Dec 03, 2013 \n* [Processing Data with Java SE 8 Streams, Part 1](http://www.oracle.com/technetwork/articles/java/ma14-java-se-8-streams-2177646.html)\n* [Lazy sequences implementation for Java 8](https://github.com/nurkiewicz/LazySeq)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxp-forge%2Fsequence","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxp-forge%2Fsequence","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxp-forge%2Fsequence/lists"}