{"id":21374952,"url":"https://github.com/peekandpoke/psi","last_synced_at":"2025-06-22T18:36:29.355Z","repository":{"id":31778161,"uuid":"35344530","full_name":"PeekAndPoke/psi","owner":"PeekAndPoke","description":"Php Simple Iterations. Map, filter, aggregate, reduce with ease. Produce readable and reliable code without hand-written loops.","archived":false,"fork":false,"pushed_at":"2019-05-06T19:16:16.000Z","size":2117,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-07-04T16:45:57.070Z","etag":null,"topics":["functional-programming","immutability","php"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PeekAndPoke.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-05-09T20:39:34.000Z","updated_at":"2020-05-14T21:20:43.000Z","dependencies_parsed_at":"2022-08-23T20:51:02.292Z","dependency_job_id":null,"html_url":"https://github.com/PeekAndPoke/psi","commit_stats":null,"previous_names":[],"tags_count":40,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeekAndPoke%2Fpsi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeekAndPoke%2Fpsi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeekAndPoke%2Fpsi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeekAndPoke%2Fpsi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PeekAndPoke","download_url":"https://codeload.github.com/PeekAndPoke/psi/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225869907,"owners_count":17537169,"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","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":["functional-programming","immutability","php"],"created_at":"2024-11-22T08:46:14.975Z","updated_at":"2024-11-22T08:46:16.236Z","avatar_url":"https://github.com/PeekAndPoke.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Code Coverage](https://scrutinizer-ci.com/g/PeekAndPoke/psi/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/PeekAndPoke/psi/?branch=master)\n[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/PeekAndPoke/psi/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/PeekAndPoke/psi/?branch=master)\n[![Build Status](https://scrutinizer-ci.com/g/PeekAndPoke/psi/badges/build.png?b=master)](https://scrutinizer-ci.com/g/PeekAndPoke/psi/build-status/master)\n\n# Introduction\n\nPSI helps you to write cleaner and more stable PHP-Code. Especially when it comes to iterating, filtering, mapping,\nsorting arrays or array-like data.\n\nPSI consists of multiple small operations that can be combined and chained. Doing so results in easier to read and more expressive code.\n\nPSI supports PHP versions \u003e= 7.0\n\n# TOC\n\n- [Examples](#examples)\n- [Details Docs](#detailed-documentation)\n- [UnitTests](#unittests)\n- [Releases](#releases)\n- [Todos and ideas](#todos-and-ideas)\n\n## Examples\n\nLet's have a look at some examples.\n\n### Get all adults \n\n```php\n/** @var Person[] $input */\n$input = $service-\u003egetStuff();\n\n/** @var Person[] $result */\n$result = Psi::it($input)\n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003efilter(function (Person $p) { return $p-\u003egetAge() \u003e= 18; })\n  -\u003etoArray();\n```\n\nIn plain PHP this might looks like:\n\n```php\n/** @var Person[] $input */\n$ipnut = $service-\u003egetStuff();\n\n$result = [];\n\nforeach ($input as $item) {\n  \n  if ($item instanceof Person \u0026\u0026 $item-\u003egetAge() \u003e= 18) {\n    $result[] = $item\n  }\n}\n \n```\n\n### Get all adults and sort them by age\n\n```php\n/** @var Person[] $input */\n$input = $service-\u003egetStuff();\n\n/** @var Person[] $result */\n$result = Psi::it($input)\n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003efilter(function (Person $p) { return $p-\u003egetAge() \u003e= 18; })\n  -\u003esortBy(function (Person $p) { return $p-\u003egetAge(); })\n  -\u003etoArray();\n```\n\nIn plain PHP this might looks like:\n\n```php\n/** @var Person[] $input */\n$ipnut = $service-\u003egetStuff();\n\n$result = [];\n\nforeach ($input as $item) {\n  \n  if ($item instanceof Person \u0026\u0026 $item-\u003egetAge() \u003e= 18) {\n    $result[] = $item\n  }\n}\n\nusort($result, function (Person $p1, Person $p2) {\n \n  return $p1-\u003egetAge() \u003c=\u003e $p2-\u003egetAge(); \n}); \n```\n\n### Get all adults and sort them by age descending\n\n```php\n/** @var Person[] $input */\n$input = $service-\u003egetStuff();\n\n/** @var Person[] $result */\n$result = Psi::it($input)\n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003efilter(function (Person $p) { return $p-\u003egetAge() \u003e= 18; })\n  -\u003esortBy(function (Person $p) { return $p-\u003egetName(); })\n  -\u003ereverse()\n  -\u003etoArray();\n```\n\n## Mapping\n\nWith *Psi::map()* you can convert incoming data.\n\nFor example lets convert all persons to ints (the persons age)\n\n```php\n/** @var Person[] $input */\n$input = $service-\u003egetStuff();\n\n$result = Psi::it($input)\n  -\u003emap(function (Person $p) { return $p-\u003egetAge(); })\n  -\u003etoArray();\n```\n\nThis might result in\n\n```\n[10, 20, 18, 31, ...]\n\n```\n\nWe could also convert each Person into something else.\n\n```php\n/** @var Person[] $input */\n$input = $service-\u003egetStuff();\n\n$result = Psi::it($input)\n  -\u003esortBy(function (Person $p) { return $p-\u003egetName(); })\n  -\u003emap(function (Person $p) { return [ $p-\u003egetName(), $p-\u003egetAge() ]; })\n  -\u003etoArray();\n```\n\nThis might result in\n\n```\n[[\"Elsa\", 20], [\"Joe\", 10], [\"John\", 18], [\"Mary\", 31], ...]\n\n```\n\n## Advanced filtering\n\nWith *Psi::filterBy()* you can combine mapping and filtering. \n\nLet's get all adults by checking the age using Psi\\IsGreaterThanOrEqual(). \n\nThe example below will also give you all Persons with an age greater than or equal to 18.\n \n```php\n$input = $service-\u003egetStuff();\n\n/** @var Person[] $result */\n$result = Psi::it($input)\n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003efilterBy(\n    function (Person $p) { return $p-\u003egetAge(); }, // map the input\n    new Psi\\IsGreaterThanOrEqual(18)               // apply filter on the mapped value\n  )\n  -\u003etoArray();\n```\n\n## Check if all or any elements match\n\nWith *Psi::all()* you can check if all elements match the given condition \n\n```php\n$result = Psi::it([1, 1, 1])\n    -\u003eall(new Psi\\IsEqualTo(1));  // true, all elements are equal to 1\n\n$result = Psi::it([1, 1, 1])\n    -\u003eall(function ($it) { return $it === 1 });  // true, all elements are equal to 1\n\n$result = Psi::it([1, 2, 3])\n    -\u003eall(new Psi\\IsEqualTo(1));  // false, not all elements are equal to 1\n\n$result = Psi::it([])\n    -\u003eall(new Psi\\IsEqualTo(1));  // true, since no element does not match the condition\n```\n\nWith *Psi::any()* you can check if there is at least one element matching the condition\n\n```php\n$result = Psi::it([2, 1, 4])\n    -\u003eany(new Psi\\IsEqualTo(1));  // true, there is one element that is equal to 1\n\n$result = Psi::it([2, 1, 4])\n    -\u003eany(function ($it) { return $it === 1 });  // true, there is one element that is equal to 1\n\n$result = Psi::it([2, 3, 4])\n    -\u003eany(new Psi\\IsEqualTo(1));  // false, there is no element that is equal to 1\n\n$result = Psi::it([])\n    -\u003eany(new Psi\\IsEqualTo(1));  // false, when there is no element in the list, then none can match\n```\n\n## Grouping\n\nLet's group all persons by their age\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var Person[] $result */\n$result = Psi::it($input)\n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003egroupBy(\n    function (Person $p) { return $p-\u003egetAge(); },   // define the group\n  )\n  -\u003etoKeyValueArray();                               // toKeyValueArray() will preserve keys, in our case the age-groups\n\nvar_dump($result);\n```\nThis might output:\n\n```\narray(3) {\n  [7] =\u003e\n  array(2) { \n    [0] =\u003e\n    object(Person) ...\n    [1] =\u003e\n    object(Person) ...\n  }\n  [15] =\u003e\n  array(1) {\n    [0] =\u003e\n    object(Person) ...\n    ...\n  }\n  [21] =\u003e\n  array (2) {\n    ...\n  }\n  ...  \n}\n```\n\n\n## Multiple inputs\n\nYou can pass multiple array or array-like parameters to Psi::it(... $inputs) \n\n```php\n/** @var Person[] $result */\n$result = Psi::it(\n    $service-\u003egetStuff(),\n    $service-\u003egetMoreStuff(),\n    $service-\u003egetEvenMoreStuff()    \n  )\n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003etoArray();\n```\n\n## Skip and Limit\n\nLet's get up to 5 adults but skip the first 10:\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var Person[] $result */\n$result = Psi::it($input)\n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003efilter(function (Person $p) { return $p-\u003egetAge() \u003e= 18; })\n  -\u003eskip(10)\n  -\u003elimit(5)\n  -\u003etoArray();\n```\n\nOr let's skip the first 10 no matter what they are and then get up to 5 adults\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var Person[] $result */\n$result = Psi::it($input)  \n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003eskip(10)\n  -\u003efilter(function (Person $p) { return $p-\u003egetAge() \u003e= 18; })\n  -\u003elimit(5)\n  -\u003etoArray();\n```\n\nOr let's skip the first 10, then get up to 5 and then filter the adults out of these\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var Person[] $result */\n$result = Psi::it($input)  \n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003eskip(10)\n  -\u003elimit(5)\n  -\u003efilter(function (Person $p) { return $p-\u003egetAge() \u003e= 18; })\n  -\u003etoArray();\n```\n\n## Count, sum, min, max, average, median\n\nLet's count the number of adults:\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var float $result */\n$result = Psi::it($input)  \n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003efilter(function (Person $p) { return $p-\u003egetAge() \u003e= 18; })\n  -\u003ecount();\n```\n\nLet's sum the age of all persons:\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var float $result */\n$result = Psi::it($input)  \n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003emap(function (Person $p) { return $p-\u003egetAge(); })\n  -\u003esum();\n```\n\nLet's get the youngest age of all people we know:\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var float $result */\n$result = Psi::it($input)  \n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003emap(function (Person $p) { return $p-\u003egetAge(); })\n  -\u003emin();\n```\n\nLet's get the oldest age of all:\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var float $result */\n$result = Psi::it($input)  \n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003emap(function (Person $p) { return $p-\u003egetAge(); })\n  -\u003emax();\n```\n\nLet's get the average age:\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var float $result */\n$result = Psi::it($input)  \n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003emap(function (Person $p) { return $p-\u003egetAge(); })\n  -\u003eavg();\n```\n\nLet's get the median age:\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var float $result */\n$result = Psi::it($input)  \n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003emap(function (Person $p) { return $p-\u003egetAge(); })\n  -\u003emedian();\n```\n\nLet's get the median age of all adults:\n\n```php\n$input = $service-\u003egetStuff();\n\n/** @var float $result */\n$result = Psi::it($input)  \n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003efilter(function (Person $p) { return $p-\u003egetAge() \u003e= 18; })\n  -\u003emap(function (Person $p) { return $p-\u003egetAge(); })\n  -\u003emedian();\n```\n\n## Get first, last, random\n\nLet's get the first person that fits a certain condition (name starting with \"A\")\n\n```php\n/** @var Person|null $result */\n$result = Psi::it(input)\n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003efilterBy(\n    function(function (Person $p) { return $p-\u003egetName(); }),\n    new Psi\\Str\\IsStartingWith('A')\n  )\n  -\u003egetFirst()\n    \n```\n\nLet's get the last person that fits a certain condition (name starting with \"A\")\n\n```php\n/** @var Person|null $result */\n$result = Psi::it(input)\n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003efilterBy(\n    function(function (Person $p) { return $p-\u003egetName(); }),\n    new Psi\\Str\\IsStartingWith('A')\n  )\n  -\u003egetLast()\n    \n```\n\nLet's get a random person that fits a certain condition (name starting with \"A\")\n\n```php\n/** @var Person|null $result */\n$result = Psi::it(input)\n  -\u003efilter(new Psi\\IsInstanceOf(Person::class))\n  -\u003efilterBy(\n    function(function (Person $p) { return $p-\u003egetName(); }),\n    new Psi\\Str\\IsStartingWith('A')\n  )\n  -\u003egetRandom()\n    \n```\n\n\n# Detailed Documentation\n\n## Filters - type checks\n\n### IsArray and IsNotArray\n\nFilters for Arrays using is_array()\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsArray())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotArray())-\u003etoArray();\n```\n\n### IsBool and IsNotBool\n\nFilter for Booleans using is_bool()\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsBool())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotBool())-\u003etoArray();\n```\n\n### IsCallable and IsNotCallable\n\nFilter for Callables using is_callable()\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsCallable())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotCallable())-\u003etoArray();\n```\n\n### IsDateString and IsNotDateString\n\nChecks if the given string is a string that would be understood be new \\DateTime($str)\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsDateString())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotDateString())-\u003etoArray();\n```\n\n### IsEmpty and IsNotEmpty\n\nFilter for empty things using empty()\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsEmpty())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotEmpty())-\u003etoArray();\n```\n\n### IsInstanceOf and IsNotInstanceOf\n\nFilter for class instance\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsInstanceOf())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotInstanceOf())-\u003etoArray();\n```\n\n### IsInteger and IsNotInteger\n\nFilter for integers using is_int()\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsInteger())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotInteger())-\u003etoArray();\n```\n\n### IsIntegerString and IsNotIntegerString\n\nFilter for strings that contain an integer\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsIntegerString())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotIntegerString())-\u003etoArray();\n```\n\n### IsNull and IsNotNull\n\nFilter for nulls\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNull())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotNull())-\u003etoArray();\n```\n\n### IsNumeric and IsNotNumeric\n\nFilter for numeric values using is_numeric()\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNull())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotNull())-\u003etoArray();\n```\n\n### IsObject and IsNotObject\n\nFilter for objects\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsObject())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotObject())-\u003etoArray();\n```\n\n### IsResource and IsNotResource\n\nFilter for resources\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsResource())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotResource())-\u003etoArray();\n```\n\n### IsScalar and IsNotScalar\n\nFilter for scalar values using is_scalar()\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsResource())-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotResource())-\u003etoArray();\n```\n\n## Filter - comparison\n\n\n### IsEqualTo and IsNotEqualTo\n\nFilter for NON type safe eqaulity (==). See IsSame / IsNotSame for === comparison\n\n```php\n$result = Psi::it($input)-\u003efilter(new Psi\\IsEqualTo(\"Summer\"))-\u003etoArray();\n\n$result = Psi::it($input)-\u003efilter(new Psi\\IsNotEqualTo(\"Winter\"))-\u003etoArray();\n```\n\n# UnitTests\n\nFirst install all dependencies\n\n```bash\n./composer install\n```\n\nThen run all tests\n\n```bash\nvendor/bin/phpunit\n```\n\n\n# Releases\n\n## new in v1.2.0\n\n*REMOVED PHP 5.6 SUPPORT*\n\nAdded \n- Psi::all()\n- Psi::any()\n\n\n## new in v1.1.0\n\nMoved mapper ToFloat, ToInteger, ToString to Psi\\Map\\...\n\nOld versions are kept for compatibility and marked as deprecated.\n\n## new in v0.6.4\n\n### Psi::chunk\n\nWill split the stream into chunks of the given size.\n\n```php\nPsi::it(range(0, 10))\n  -\u003echunk(3)\n  -\u003etoArray();\n```\n\nwill result in\n\n``` \n[\n  [0, 1, 2], \n  [3, 4, 5], \n  [6, 7, 8], \n  [9, 10]\n]\n```\n\n### Psi::skip\n\nSkips the first n elements in the current stream\n\n```php\nPsi::it(range(0, 20))\n  -\u003efilter(new IsMultipleOf(2))\n  -\u003eskip(5)\n  -\u003etoArray();\n```\n\nwill result in \n\n``` \n[10, 12, 14, 16, 18, 20]\n```\n\n### Psi::limit\n\nLimits the result to the first n element in the current stream\n\n```php\nPsi::it(range(0, 20))\n  -\u003efilter(new IsMultipleOf(2))\n  -\u003elimit(5)\n  -\u003etoArray();\n```\n\nwill result in \n\n``` \n[0, 2, 4, 6, 8]\n```\n\n\n### Psi::takeWhile\n\nTake all elements of the input stream while the condition is met\n\n```php\nPsi::it(range(0, 20))\n  -\u003etakeWhile(new Psi\\IsLessThan(5))\n  -\u003etoArray();\n```\n\nwill result in\n\n``` \n[0, 1, 2, 3, 4]\n```\n\n\n### Psi::takeUntil\n\nTake all elements of the input stream until the condition is met\n\n```php\nPsi::it(range(0, 20))\n  -\u003etakeUntil(new Psi\\IsGreaterThan(5))\n  -\u003etoArray();\n``` \n\nwill result in\n\n``` \n[0, 1, 2, 3, 4, 5]\n```\n\n### Psi::getLast\n\nGet the last element of the stream.\n\n```php\nPsi::it([1, 2, 3])\n  -\u003efilter(function ($i) { return $i \u003c 3; })\n  -\u003egetLast()\n```\n\nwill result in\n\n```php\n2\n```\n\n### Psi::getRandom\n\nWill select a random element from the stream.\n\n```php\nPsi::it([1, 2, 3])\n  -\u003efilter(function ($i) { return $i \u003c 3; })\n  -\u003egetRandom()\n```\n\nwill result in\n\n```\n1 or 2\n```\n\n### Num::IsMultipleOf and Num::IsNotMultipleOf\n\nFilters all numbers that are a multiple of the given factor\n\n```php\nPsi::it([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])\n  -\u003efilter(new Psi\\Num\\IsMultipleOf(3))\n  -\u003etoArray();\n```\n\nwill result in\n\n```\n[0, 3, 6, 9] \n```\n\n### Num::IsPrime and Num::IsNotPrime\n\nFilters all number that are prime number.\n\nCAUTION: do not use this impl for big numbers, a it can be very slow.\n\n```php\nPsi::it(range(0, 30))\n    -\u003efilter(new Psi\\Num\\IsPrime())\n    -\u003etoArray();\n```\n\nwill result in\n\n``` \n[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]\n```\n\n## new in v0.6.3\n\n### Psi::filterBy()\n\nIn order to by able to use all other matchers on nested property / values of input objects, the \nmethod Psi::filterBy() was added\n\n```php\n$result = Psi::it($persons)\n  -\u003efilterBy(\n    function (Person $p) { return $p-\u003egetAge(); },\n    new IsLessThan(18)\n  )\n  -\u003etoArray()\n``` \n\n### Psi::uniqueBy \n\nFinds unique elements by first passing them through a mapper.\n\n```php\n$result = Psi::it($persons)\n  -\u003euniqueBy(\n    function (Person $p) { return $person-\u003egetName(); }\n  )\n  -\u003etoArray();\n```\n\n### ToFloat\n\nMaps inputs to floats.\n\n```php\n$result = Psi::it($values)\n  -\u003emap(new Psi\\ToFloat())\n  -\u003etoArray();\n```\n\n### ToInteger\n\nMaps inputs to integers.\n\n```php\n$result = Psi::it($values)\n  -\u003emap(new Psi\\ToInteger())\n  -\u003etoArray();\n```\n\n### ToString\n\nMaps inputs to strings.\n\n```php\n$result = Psi::it($values)\n  -\u003emap(new Psi\\ToString())\n  -\u003etoArray();\n```\n\n### Str::IsStartingWith and Str::IsNotStartingWith - with or with case\n\nFilters all strings starting with the given needle. By default case-sensitive. \nPass false as the second parameter to be non-case-sensitive.\n\n```php\n$result = Psi::it($values)\n  -\u003efilter(new Psi\\Str\\IsStartingWith('a'))\n  -\u003etoArray();\n\n$result = Psi::it($values)\n  -\u003efilter(new Psi\\Str\\IsNotStartingWith('a', false))\n  -\u003etoArray();\n```\n\n### Str::IsEndingWith and Str::IsNotEndingWith - with or without case\n\nFilters all strings ending with the given needle. By default case-sensitive. \nPass false as the second parameter to be non-case-sensitive.\n\n```php\n$result = Psi::it($values)\n  -\u003efilter(new Psi\\Str\\IsEndingWith('a'))\n  -\u003etoArray();\n\n$result = Psi::it($values)\n  -\u003efilter(new Psi\\Str\\IsNotEndingWith('a', false))\n  -\u003etoArray();\n```\n\n### Str::IsContaining and Str::IsNotContaining - with or without case\n\nFilters all strings containing the given needle. By default case-sensitive. \nPass false as the second parameter to be non-case-sensitive.\n\n```php\n$result = Psi::it($values)\n  -\u003efilter(new Psi\\Str\\IsContaining('a'))\n  -\u003etoArray();\n\n$result = Psi::it($values)\n  -\u003efilter(new Psi\\Str\\IsNotContaining('a', false))\n  -\u003etoArray();\n```\n\n### Str::IsMatchingRegex and Str::IsNotMatchingRegex\n\nFilters all strings containing the given needle. By default case-sensitive. \nPass false as the second parameter to be non-case-sensitive.\n\n```php\n$result = Psi::it($values)\n  -\u003efilter(new Psi\\Str\\IsMatchingRegex('/[0-9]{2,}'))\n  -\u003etoArray();\n\n$result = Psi::it($values)\n  -\u003efilter(new Psi\\Str\\IsNotMatchingRegex('/ABC/i'))\n  -\u003etoArray();\n```\n\n\n### Str::WithoutAccents\n\nModifies a string by replacing special characters with the \"normal\" form, e.g.\n\n```\nDragoş  -\u003e  Dragos\n\nÄrmel   -\u003e  Aermel\nBlüte   -\u003e  Bluete\nStraße  -\u003e  Strasse\n\npassé   -\u003e  passe\n```\n\n```php\n$result = Psi::it($values)\n  -\u003emap(new Psi\\Str\\WithoutAccents())\n  -\u003etoArray();\n```\n\n## new in v0.6.0 to v0.6.2\n\nThe internal folder structure was changed:\n\n- public interface live now on the root level\n- some over-engineering was removed (some classes removed)\n- interface no longer have names like \"UnaryFunctionInterface\" but \"UnaryFunction\"\n\n \n\n## new in v0.5.0\n\n### Psi::groupBy \n\n```php\nPsi::it(\n  [ ['name' =\u003e 'a', 'val' =\u003e 1], ['name' =\u003e 'a', 'val' =\u003e 2], ['name' =\u003e 'b', 'val' =\u003e 1] ]\n)\n-\u003egroupBy(\n  function ($o) { return $o['name']; }\n)\n-\u003etoArray() \n```\nwould become \n\n```php\n['a' =\u003e [ ['name' =\u003e 'a', 'val' =\u003e 1], ['name' =\u003e 'a', 'val' =\u003e 2] ], 'b' =\u003e ... ]  \n```\n\n### Psi::sortBy \n\nSort a list of objects by one of their properties, e.g. sorting persons by their age\n\n```\n$result = Psi::it($values)\n  -\u003efilterBy(\n    function (Person $p) { return $p-\u003egetAge(); }\n  )\n  -\u003etoArray()\n\n```\n\n\n## Todos and ideas\n\n### general\n\n- make custom TerminalOperations possible Psi::reduce()\n\n### Unary filter functions for strings\n\nString-Mappers\n- Str::Camelize (StrToCamelCase)\n- ... camel to dashes (StrToSlug)\n- Str::UcFirst, Str::LcFirst\n- Str::StrReplace\n- Str::StrMbReplace\n- Str::StrRegexReplace\n- Str::StrMbRegexReplace\n\n... for PHP-Types ... LocalDate::isSameDay\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeekandpoke%2Fpsi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpeekandpoke%2Fpsi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpeekandpoke%2Fpsi/lists"}