├── .github └── CONTRIBUTING.md ├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── SUMMARY.md ├── composer.json ├── docs ├── instalation.md ├── iterables.md ├── querying_trees.md └── quickstart.md ├── phpunit.xml.dist ├── src ├── AbstractCollection.php ├── AbstractConstCollectionArray.php ├── CollectionInterface.php ├── Comparer │ ├── NumericKeyComparer.php │ └── StringComparer.php ├── ConstCollectionInterface.php ├── ConstIndexAccessInterface.php ├── ConstMapAccessInterface.php ├── ConstMapInterface.php ├── ConstSetAccessInterface.php ├── ConstSetInterface.php ├── ConstVectorInterface.php ├── Container.php ├── Enumerable.php ├── Exception │ ├── ElementAlreadyExists.php │ ├── EmptyException.php │ ├── Exception.php │ ├── InvalidArgumentException.php │ ├── InvalidOperationException.php │ ├── KeyException.php │ ├── LookupException.php │ ├── StateException.php │ └── TypeException.php ├── Generic │ └── ComparerInterface.php ├── Immutable │ ├── ImmMap.php │ ├── ImmSet.php │ └── ImmVector.php ├── IndexAccessInterface.php ├── Indexish.php ├── Iterator │ ├── LazyConcatIterable.php │ ├── LazyConcatIterator.php │ ├── LazyFilterIterable.php │ ├── LazyFilterIterator.php │ ├── LazyFilterKeyedIterable.php │ ├── LazyFilterKeyedIterator.php │ ├── LazyFilterWithKeyIterable.php │ ├── LazyFilterWithKeyIterator.php │ ├── LazyIterableTrait.php │ ├── LazyKeyedIterableTrait.php │ ├── LazyKeysIterable.php │ ├── LazyKeysIterator.php │ ├── LazyMapIterable.php │ ├── LazyMapIterator.php │ ├── LazyMapKeyedIterable.php │ ├── LazyMapKeyedIterator.php │ ├── LazyMapWithKeyIterable.php │ ├── LazyMapWithKeyIterator.php │ ├── LazySkipIterable.php │ ├── LazySkipIterator.php │ ├── LazySkipKeyedIterable.php │ ├── LazySkipKeyedIterator.php │ ├── LazySkipWhileIterable.php │ ├── LazySkipWhileIterator.php │ ├── LazySkipWhileKeyedIterable.php │ ├── LazySkipWhileKeyedIterator.php │ ├── LazySliceIterable.php │ ├── LazySliceIterator.php │ ├── LazySliceKeyedIterable.php │ ├── LazySliceKeyedIterator.php │ ├── LazyTakeIterable.php │ ├── LazyTakeIterator.php │ ├── LazyTakeKeyedIterable.php │ ├── LazyTakeKeyedIterator.php │ ├── LazyTakeWhileIterable.php │ ├── LazyTakeWhileIterator.php │ ├── LazyTakeWhileKeyedIterable.php │ ├── LazyTakeWhileKeyedIterator.php │ ├── LazyValuesIterable.php │ ├── LazyValuesIterator.php │ ├── LazyZipIterable.php │ ├── LazyZipIterator.php │ ├── LazyZipKeyedIterable.php │ ├── LazyZipKeyedIterator.php │ ├── MapIterator.php │ ├── PairIterator.php │ ├── SetIterator.php │ └── VectorIterator.php ├── KeyedContainer.php ├── KeyedIterable.php ├── KeyedIterator.php ├── KeyedTraversable.php ├── Map.php ├── MapAccessInterface.php ├── MapInterface.php ├── OutputCollectionInterface.php ├── Pair.php ├── Queue.php ├── QueueInterface.php ├── Set.php ├── SetAccessInterface.php ├── SetInterface.php ├── SortTrait.php ├── Stack.php ├── StackInterface.php ├── Traits │ ├── CommonContainerMethodsTrait.php │ ├── CommonImmMutableContainerTrait.php │ ├── CommonMutableContainerTrait.php │ ├── ConstMapLikeTrait.php │ ├── ConstSetLikeTrait.php │ ├── ConstVectorLikeTrait.php │ ├── GuardTrait.php │ ├── ImmMapLikeTrait.php │ ├── ImmSetLikeTrait.php │ ├── ImmVectorLikeTrait.php │ ├── MapLikeTrait.php │ ├── SetLikeTrait.php │ └── VectorLikeTrait.php ├── Vector.php └── VectorInterface.php └── tests ├── CollectionSerializerTest.php ├── CollectionsTestCase.php ├── Comparer ├── NumericKeyComparerTest.php └── StringComparerTest.php ├── EnumerableTest.php ├── Iterator └── ArrayIteratorTest.php ├── MapTest.php ├── QueueTest.php ├── SetTest.php ├── StackTest.php └── VectorTest.php /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/italolelis/collections). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ phpunit 29 | ``` 30 | 31 | 32 | **Happy coding**! 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor 3 | *.log 4 | ._* 5 | .~lock.* 6 | .buildpath 7 | .project 8 | .settings 9 | /build/ 10 | /bin/ 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.6 5 | - 7.0 6 | - 7.1 7 | - nightly 8 | - hhvm 9 | 10 | matrix: 11 | fast_finish: true 12 | allow_failures: 13 | - php: nightly 14 | 15 | before_script: 16 | - composer self-update 17 | - composer install --prefer-dist 18 | 19 | script: 20 | - phpunit --coverage-clover build/logs/clover.xml --configuration ./phpunit.xml.dist ./tests 21 | 22 | after_script: 23 | - php bin/codacycoverage clover build/logs/clover.xml 24 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## 6.0.0 - unreleased 5 | 6 | ### Add 7 | - Lazy Iterator API, many new Lazy iterators that speed up the functional approach on the collections 8 | - `Pair` collection, that helps a `Map` to add a key value pair 9 | 10 | ## Removed 11 | - `tryGet()` method, now you need to use `get()` 12 | 13 | ## 5.0.0 - 2016-04-06 14 | ### Add 15 | - `Set` class 16 | 17 | ### Deprecated 18 | - Deprecated `tryGet()` method, now we can use the `get()` 19 | 20 | ### Fixed 21 | - `toKeysArray` bug 22 | - Immutable API bug 23 | - `concat()` method bug 24 | - `removeKey()` bug 25 | 26 | ## 4.1.0 - 2015-06-03 27 | ### Add 28 | - Added to all collections the JsonSerializable interface. 29 | 30 | ### Updated 31 | - All collections that extends from ArrayCollection now have the toArrayKeys method. 32 | 33 | ## 4.0.0 - 2015-02-21 34 | ### Add 35 | - Added Reactive Extension Trait. 36 | - Added unfold method, almost like flatMap. 37 | - Added BinaryTree data structure. 38 | - Added AvlTree data structure. 39 | - Added LinkedQueue data structure. 40 | - Added LinkedStack data structure. 41 | 42 | ### Changed 43 | - The match method now don't receive a Criteria object but uses a callable instead. 44 | - Now dictionary act as a HashMap, which can accept any type of key. 45 | - The *toKeysArray* method now is only available in MapInterface. 46 | 47 | ## Removed 48 | - Removed the Expression Search API 49 | 50 | ## 3.2.0 - 2015-02-14 51 | ### Add 52 | - Added flatMap method, just like the Scala and Javascript implementation. 53 | 54 | ### Changed 55 | - The default Queue implementation uses Doubly Linked List. 56 | - The default Stack implementation uses Doubly Linked List. 57 | 58 | ### Deprecated 59 | - Deprecated *slice* method, now we can use the *take*, this is part of the Reactive Extensions initiative. 60 | - Deprecated Expression search API 61 | 62 | ## 3.1.2 - 2014-09-08 63 | ### Changed 64 | - Changed the array_merge_recursive to array_merge from the *concat* method cause was causing errors. 65 | 66 | ## 3.1.1 - 2014-09-05 67 | ### Changed 68 | - Ajusting tests for the Dictionary class, which wasn't expecting the correct exception class. 69 | 70 | ### Removed 71 | - Removing nbproject form gitignore. 72 | 73 | ## 3.1.0 - 2014-08-27 74 | ### Fixed 75 | - All the interfaces bugs which waren't being called correctly. 76 | 77 | ## 3.0.0 - 2014-08-26 78 | ### Update 79 | - Changed all interfaces names to PSR (using the *Interface* suffix). 80 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 italolelis 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Collections 2 | 3 | [![Build Status](https://travis-ci.org/italolelis/collections.svg?style=flat-square)](https://travis-ci.org/italolelis/collections) 4 | [![Scrutinizer Code Quality](http://img.shields.io/scrutinizer/g/italolelis/collections.svg?style=flat-square)](https://scrutinizer-ci.com/g/italolelis/collections/) 5 | [![Code Coverage](http://img.shields.io/scrutinizer/coverage/g/italolelis/collections.svg?style=flat-square)](https://scrutinizer-ci.com/g/italolelis/collections/) 6 | [![Latest Stable Version](http://img.shields.io/packagist/v/easyframework/collections.svg?style=flat-square)](https://packagist.org/packages/easyframework/collections) 7 | [![Downloads](https://img.shields.io/packagist/dt/easyframework/collections.svg?style=flat-square)](https://packagist.org/packages/easyframework/collections) 8 | 9 | Collections Abstraction library for PHP 10 | 11 | The Collection library is one of the most useful things that many modern languages has, but for some reason PHP doesn't has a built in collection layer. 12 | 13 | For that reason we created Collections, an incredible library that gathers the best of .NET's and Java's collections patterns and 14 | unify it with PHP array power. 15 | 16 | Take a look and see what we're talking about!! 17 | 18 | ## Install 19 | 20 | ```bash 21 | composer require easyframework/collections 22 | ``` 23 | 24 | ## Usage 25 | 26 | ### The Collection Class 27 | 28 | The Collection represents the List in .NET language or simply non-associative arrays in php: 29 | 30 | ```php 31 | $person1 = new \stdClass(); 32 | $person1->name = 'John'; 33 | $person1->age = 25; 34 | 35 | $person2 = new \stdClass(); 36 | $person2->name = 'Maria'; 37 | $person2->age = 30; 38 | 39 | $person3 = new \stdClass(); 40 | $person3->name = 'Anderson'; 41 | $person3->age = 15; 42 | 43 | $collection = new Collections\Vector(); 44 | $collection->add($person1); 45 | $collection->add($person2); 46 | $collection->add($person3); 47 | 48 | $collection->filter(function($person){ 49 | return $person->age > 18; 50 | })->each(function($item){ 51 | echo $item->name; //John and Maria 52 | }); 53 | ``` 54 | 55 | ## Contributing 56 | 57 | Please see [CONTRIBUTING](https://github.com/italolelis/collections/blob/master/CONTRIBUTING.md) for details. 58 | 59 | ## License 60 | 61 | The MIT License (MIT). Please see [License File](https://github.com/italolelis/collections/blob/master/LICENSE) for more information. 62 | 63 | ### Documentation 64 | 65 | More information can be found in the online documentation at 66 | https://italolelis.gitbooks.io/collections. 67 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [Instalation](docs/instalation.md) 5 | * [Quickstart](docs/quickstart.md) 6 | * [Iterating](docs/iterables.md) 7 | * [Querying Trees](docs/querying_trees.md) 8 | 9 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "easyframework/collections", 3 | "description": "Collections Abstraction library for PHP", 4 | "type": "library", 5 | "license": "MIT", 6 | "keywords": [ 7 | "framework", 8 | "easy", 9 | "generics", 10 | "collection" 11 | ], 12 | "homepage": "https://github.com/italolelis/collections", 13 | "authors": [ 14 | { 15 | "name": "Ítalo Lelis de Vietro", 16 | "email": "italolelis@gmail.com" 17 | } 18 | ], 19 | "require": { 20 | "php": ">=5.6.0", 21 | "easyframework/generics": "~2.0" 22 | }, 23 | "require-dev": { 24 | "phpunit/phpunit": "~5.0", 25 | "codacy/coverage": "dev-master" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Collections\\": "src/" 30 | } 31 | }, 32 | "autoload-dev": { 33 | "psr-4": { 34 | "Tests\\Collections\\": "tests/" 35 | } 36 | }, 37 | "config": { 38 | "bin-dir": "bin" 39 | }, 40 | "extra": { 41 | "branch-alias": { 42 | "dev-master": "6.0-dev" 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /docs/instalation.md: -------------------------------------------------------------------------------- 1 | # Instalation 2 | 3 | The recommended way to install Collections is with [Composer](http://getcomposer.org). Composer is a dependency management tool for PHP that allows you to declare the dependencies your project needs and installs them into your project. 4 | 5 | ```bash 6 | composer require easyframework/collections 7 | ``` 8 | 9 | You can find out more on how to install Composer, configure autoloading, and other best-practices for defining dependencies at [getcomposer.org](http://getcomposer.org). 10 | -------------------------------------------------------------------------------- /docs/iterables.md: -------------------------------------------------------------------------------- 1 | # Iterating 2 | 3 | Throughout the examples we're going to use this dataset 4 | 5 | ```php 6 | use Collection\Map; 7 | 8 | $data = [ 9 | [ 10 | "id" => 70111470, 11 | "title" => "Die Hard", 12 | "boxart" => "http://cdn-0.nflximg.com/images/2891/DieHard.jpg", 13 | "uri" => "http://api.netflix.com/catalog/titles/movies/70111470", 14 | "rating" => [4.0], 15 | "bookmark" => [] 16 | ], 17 | [ 18 | "id" => 654356453, 19 | "title" => "Bad Boys", 20 | "boxart" => "http://cdn-0.nflximg.com/images/2891/BadBoys.jpg", 21 | "uri" => "http://api.netflix.com/catalog/titles/movies/70111470", 22 | "rating" => [5.0], 23 | "bookmark" => [{ "id" => 432534, "time" => 65876586 }] 24 | ], 25 | [ 26 | "id" => 65432445, 27 | "title" => "The Chamber", 28 | "boxart" => "http://cdn-0.nflximg.com/images/2891/TheChamber.jpg", 29 | "uri" => "http://api.netflix.com/catalog/titles/movies/70111470", 30 | "rating" => [4.0], 31 | "bookmark" => [] 32 | ] 33 | ]; 34 | $videos = new Map($data); 35 | ``` 36 | 37 | ## Projecting Collections 38 | 39 | Applying a function to a value and creating a new value is called a projection. To project one iterable into another, we apply a projection function to each item in the collection and collect the results in a new collection. 40 | 41 | ### Each 42 | 43 | ```php 44 | $videoAndTitlePairs = new Map(); 45 | 46 | $videos->each(function ($video) { 47 | $videoAndTitlePairs->addAll(["id" => $video["id"], "title" => $video["title"]]); 48 | }); 49 | ``` 50 | 51 | ### Map 52 | 53 | To make projections easier, lets add a `map()` function to the game. Map accepts the projection function to be applied to each item in the source collection, and returns the projected collection. 54 | 55 | Lets use map to project a collection of videos into a collection of [id, title]: 56 | 57 | ```php 58 | $new = $videos->map(function ($video) { 59 | return [ 60 | "id" => $video["id"], 61 | "title" => $video["title"] 62 | ]; 63 | }); 64 | ``` 65 | 66 | The `map()` method will create a new iterator which lazily creates the resulting items when iterated. 67 | 68 | ### Filter 69 | 70 | Like projection, filtering a collection is also a common operation. To filter a collection we apply a test to each item in the iterable and collect the items that pass into a new iterable. 71 | 72 | Lets filter and map to collect the ids of videos that have a rating of 5.0 73 | 74 | ```php 75 | use Collection\Map; 76 | 77 | $topRatedVideos = $videos->filter(function ($video) { 78 | return $video["rating"] === 5.0; 79 | })->map(function ($video) { 80 | return $video["rating"] ; 81 | }); 82 | ``` 83 | 84 | -------------------------------------------------------------------------------- /docs/querying_trees.md: -------------------------------------------------------------------------------- 1 | # Querying Trees 2 | 3 | Sometimes, in addition to flat collections, we need to query trees. Trees pose a challenge because we need to flatten them into collections in order to apply `filter()` and `map()` operations on them. In this section we'll define a `concatAll()` function that we can combine with `map()` and `filter()` to query trees. 4 | 5 | ```php 6 | $data = [ 7 | [ 8 | "name" => "New Releases", 9 | "videos" => [ 10 | [ 11 | "id" => 70111470, 12 | "title" => "Die Hard", 13 | "boxart" => "http://cdn-0.nflximg.com/images/2891/DieHard.jpg", 14 | "uri" => "http://api.netflix.com/catalog/titles/movies/70111470", 15 | "rating" => 4.0, 16 | "bookmark" => [] 17 | ], 18 | [ 19 | "id" => 654356453, 20 | "title" => "Bad Boys", 21 | "boxart" => "http://cdn-0.nflximg.com/images/2891/BadBoys.jpg", 22 | "uri" => "http://api.netflix.com/catalog/titles/movies/70111470", 23 | "rating" => 5.0, 24 | "bookmark" => [[ id:432534, time:65876586 ]] 25 | ] 26 | ] 27 | ], 28 | [ 29 | "name" => "Dramas", 30 | "videos" => [ 31 | [ 32 | "id" => 65432445, 33 | "title" => "The Chamber", 34 | "boxart" => "http://cdn-0.nflximg.com/images/2891/TheChamber.jpg", 35 | "uri" => "http://api.netflix.com/catalog/titles/movies/70111470", 36 | "rating" => 4.0, 37 | "bookmark" => [] 38 | ], 39 | [ 40 | "id" => 675465, 41 | "title" => "Fracture", 42 | "boxart" => "http://cdn-0.nflximg.com/images/2891/Fracture.jpg", 43 | "uri" => "http://api.netflix.com/catalog/titles/movies/70111470", 44 | "rating" => 5.0, 45 | "bookmark" => [[ "id" => 432534, "time" => 65876586 ]] 46 | ] 47 | ] 48 | ] 49 | ]; 50 | $movieLists = new Map($data); 51 | 52 | $flattenVideos = $movieLists->map(function($movieList) { 53 | return $movieList["videos"]->map(function($video) { 54 | return $video["id"]; 55 | }); 56 | })->concatAll(); 57 | ``` -------------------------------------------------------------------------------- /docs/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart 2 | 3 | This page provides a quick introduction to Collections and introductory examples. 4 | 5 | If you have not already installed, Collections, head over to the `installation` page. 6 | 7 | ## Vector 8 | 9 | The Vector represents the List in `.NET` language or non-associative arrays in php: 10 | 11 | ```php 12 | use Collections\Vector; 13 | 14 | $person1 = new \stdClass(); 15 | $person1->name = 'John'; 16 | $person1->age = 25; 17 | 18 | $person2 = new \stdClass(); 19 | $person2->name = 'Maria'; 20 | $person2->age = 30; 21 | 22 | $person3 = new \stdClass(); 23 | $person3->name = 'Anderson'; 24 | $person3->age = 15; 25 | 26 | $collection = new Collections\Vector(); 27 | $collection->add($person1); 28 | $collection->add($person2); 29 | $collection->add($person3); 30 | 31 | $collection->filter(function($person){ 32 | return $person->age > 18; 33 | })->each(function($item){ 34 | echo $item->name; //John and Maria 35 | }); 36 | ``` 37 | 38 | Lets continue with the example above and count how many elements we have! 39 | 40 | ```php 41 | echo $collection->count(); 42 | ``` 43 | 44 | Great, now we know how to run through a collection and how to count it, but these are pretty simple things to do, 45 | so lets sort them: 46 | 47 | ```php 48 | use Collections\Vector; 49 | use Collections\Comparer\StringComparer; 50 | 51 | $collection->sort(); //by default the sort is by the keys 52 | $collection->sort(new StringComparer()); //this will sort by alfabetic order 53 | $collection->sort(new YourCustomComparer()); //you can create your own custom comparer to sort your collection 54 | ``` 55 | 56 | Yeah that is great, isn't it? But we can do much more things, now lets search for someone in the collection. 57 | 58 | ```php 59 | print_r($collection->contains("John")); //returns true 60 | ``` 61 | 62 | Ok, now that we've learned the basic concepts about collections, I'll show you other type of collection called Map. 63 | 64 | ## Map 65 | 66 | The Map class is something like associative arrays in PHP, or Hash tables in other languages. 67 | 68 | ```php 69 | use Collections\Map; 70 | 71 | $dictionary = new Map(); 72 | $dictionary->add('person1', array( 73 | 'name' => 'John', 74 | 'age' => 20 75 | )); 76 | $dictionary->add('person2', array( 77 | 'name' => 'Maria', 78 | 'age' => 19 79 | )); 80 | $dictionary->add('person3', array( 81 | 'name' => 'Anderson', 82 | 'age' => 25 83 | )); 84 | 85 | $dictionary->each(function($item){ 86 | echo $key . ": " . $item['name'] . "-" . $item['age']; 87 | }); 88 | ``` 89 | 90 | We can use object as keys too. 91 | 92 | ```php 93 | use Collections\Map; 94 | 95 | $dictionary = new Map(); 96 | 97 | $object = new \stdClass(); 98 | $dictionary->add($object, 'value'); 99 | echo $dictionary->get($object); //prints 'value' 100 | ``` 101 | 102 | When one key is added we can't insert the same key again, if we want to change its value we need to use the method `set()`. Here is an example of how we can get some item based on the key; 103 | 104 | ```php 105 | print_r ($dictionary->get('person1')); //returns ['name' => John, 'age' => 20] 106 | ``` 107 | 108 | ## Working with objects 109 | 110 | To our last example we'll use objects in our collection. 111 | 112 | ```php 113 | use Collections\Vector; 114 | 115 | $collection = new Vector(); 116 | $collection->add(new Person('John', 20)); 117 | $collection->add(new Person('Peter', 20)); 118 | $collection->add(new Person('Sophie', 21)); 119 | $collection->add(new Person('Angela', 29)); 120 | $collection->add(new Person('Maria', 19)); 121 | $collection->add(new Person('Anderson', 25)); 122 | 123 | $collection->each(function($item){ 124 | echo $item->getName(); 125 | }); 126 | ``` 127 | 128 | Pretty simple, but the reason I wanted to show you objects is because of Reactive Extension API. Lets seek everyone with age 20. 129 | 130 | ```php 131 | // this will return John and Peter 132 | $people = $people->filter(function($person){ 133 | return $person->getAge() === 20; 134 | }); 135 | ``` 136 | 137 | The `map()` method will create a new collection based on the output of the callback being applied to each object in the original collection: 138 | 139 | ```php 140 | $new = $people->map(function ($person, $key) { 141 | return $person->getAge() * 2; 142 | }); 143 | 144 | // $result contains all persons with twice theirs ages; 145 | $result = $new->toArray(); 146 | ``` -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 | 15 | 16 | ./tests/ 17 | 18 | 19 | 20 | 21 | 22 | ./ 23 | 24 | ./tests/ 25 | ./vendor 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/AbstractCollection.php: -------------------------------------------------------------------------------- 1 | type exposes the following members. 8 | * 9 | * @since 2.1.0 10 | * @author Ítalo Lelis de Vietro 11 | */ 12 | interface ComparerInterface 13 | { 14 | 15 | /** 16 | * Compares two objects and returns a value indicating whether one is less than, equal to, or greater 17 | * than the other. 18 | * @param object $first The first object to compare. 19 | * @param object $second The second object to compare. 20 | * @return int A int that indicates the relative values of x and y, as shown in the following table. 21 | */ 22 | public function compare($first, $second); 23 | } 24 | -------------------------------------------------------------------------------- /src/Immutable/ImmMap.php: -------------------------------------------------------------------------------- 1 | init($array); 16 | } 17 | 18 | /** 19 | * Gets the collection's iterator 20 | * @return MapIterator 21 | */ 22 | public function getIterator() 23 | { 24 | return new MapIterator($this->container); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Immutable/ImmSet.php: -------------------------------------------------------------------------------- 1 | init($array); 16 | } 17 | 18 | /** 19 | * Gets the collection's iterator 20 | * @return SetIterator 21 | */ 22 | public function getIterator() 23 | { 24 | return new SetIterator($this->container); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Immutable/ImmVector.php: -------------------------------------------------------------------------------- 1 | init($array); 19 | } 20 | 21 | /** 22 | * Gets the collection's iterator 23 | * @return VectorIterator 24 | */ 25 | public function getIterator() 26 | { 27 | return new VectorIterator($this->container); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/IndexAccessInterface.php: -------------------------------------------------------------------------------- 1 | set($key,$value)` is semantically equivalent to `$coll[$k] = $v` 15 | * (except that set() returns the current collection). 16 | * 17 | * @param string|int $key The key to which we will set the value. 18 | * @param mixed $value The value to set. 19 | * @return IndexAccessInterface A shallow copy of the current collection with the updated the value set. 20 | */ 21 | public function set($key, $value); 22 | 23 | /** 24 | * For every element in the provided Traversable, stores a value into the current collection associated 25 | * with each key, overwriting the previous value associated with the key. 26 | * 27 | * If a key is not present the current collection that is present in the Traversable, 28 | * an exception is thrown. If you want to add a value even if a key is not present, use `addAll()`. 29 | * 30 | * @param array|\Traversable $traversable - The Traversable with the new values to set. If null is provided, no changes are made. 31 | * @return IndexAccessInterface A shallow copy of the current collection with the updated the values set. 32 | */ 33 | public function setAll($traversable); 34 | 35 | /** 36 | * Removes the specified key (and associated value) from the current collection. 37 | * If the key is not in the current collection, the current collection is unchanged. 38 | * It returns a shallow copy of the current collection, meaning changes made to the current 39 | * collection will be reflected in the returned collection. 40 | * 41 | * @param mixed $key 42 | * @return IndexAccessInterface 43 | */ 44 | public function removeKey($key); 45 | } 46 | -------------------------------------------------------------------------------- /src/Indexish.php: -------------------------------------------------------------------------------- 1 | iterable1 = $iterable1; 24 | $this->iterable2 = $iterable2; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazyConcatIterator($this->iterable1->getIterator(), $this->iterable2->getIterator()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Iterator/LazyConcatIterator.php: -------------------------------------------------------------------------------- 1 | it1 = $it1; 30 | $this->it2 = $it2; 31 | $this->currentIt = $it1; 32 | $this->state = 1; 33 | 34 | if (!$this->currentIt->valid()) { 35 | $this->currentIt = $this->it2; 36 | $this->state = 2; 37 | } 38 | } 39 | 40 | public function __clone() 41 | { 42 | $this->it1 = clone $this->it1; 43 | $this->it2 = clone $this->it2; 44 | 45 | $this->currentIt = ($this->state === 1) ? $this->it1 : $this->it2; 46 | } 47 | 48 | public function rewind() 49 | { 50 | $this->it1->rewind(); 51 | $this->it2->rewind(); 52 | $this->currentIt = $this->it1; 53 | $this->state = 1; 54 | 55 | if (!$this->currentIt->valid()) { 56 | $this->currentIt = $this->it2; 57 | $this->state = 2; 58 | } 59 | } 60 | 61 | public function valid() 62 | { 63 | return $this->currentIt->valid(); 64 | } 65 | 66 | public function next() 67 | { 68 | $this->currentIt->next(); 69 | 70 | if ($this->state === 1 && !$this->currentIt->valid()) { 71 | $this->currentIt = $this->it2; 72 | $this->state = 2; 73 | } 74 | } 75 | 76 | public function key() 77 | { 78 | return $this->currentIt->key(); 79 | } 80 | 81 | public function current() 82 | { 83 | return $this->currentIt->current(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Iterator/LazyFilterIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->fn = $fn; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazyFilterIterator($this->Enumerable->getIterator(), $this->fn); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Iterator/LazyFilterIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 20 | $this->fn = $fn; 21 | } 22 | 23 | public function __clone() 24 | { 25 | $this->it = clone $this->it; 26 | } 27 | 28 | public function rewind() 29 | { 30 | $it = $this->it; 31 | $fn = $this->fn; 32 | $it->rewind(); 33 | while ($it->valid() && !$fn($it->current())) { 34 | $it->next(); 35 | } 36 | } 37 | 38 | public function valid() 39 | { 40 | return $this->it->valid(); 41 | } 42 | 43 | public function next() 44 | { 45 | $it = $this->it; 46 | $fn = $this->fn; 47 | $it->next(); 48 | while ($it->valid() && !$fn($it->current())) { 49 | $it->next(); 50 | } 51 | } 52 | 53 | public function key() 54 | { 55 | return $this->it->key(); 56 | } 57 | 58 | public function current() 59 | { 60 | return $this->it->current(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Iterator/LazyFilterKeyedIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->fn = $fn; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return 30 | new LazyFilterKeyedIterator($this->Enumerable->getIterator(), $this->fn); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Iterator/LazyFilterKeyedIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 22 | $this->fn = $fn; 23 | } 24 | 25 | public function __clone() 26 | { 27 | $this->it = clone $this->it; 28 | } 29 | 30 | public function rewind() 31 | { 32 | $it = $this->it; 33 | $fn = $this->fn; 34 | $it->rewind(); 35 | while ($it->valid() && !$fn($it->current())) { 36 | $it->next(); 37 | } 38 | } 39 | 40 | public function valid() 41 | { 42 | return $this->it->valid(); 43 | } 44 | 45 | public function next() 46 | { 47 | $it = $this->it; 48 | $fn = $this->fn; 49 | $it->next(); 50 | while ($it->valid() && !$fn($it->current())) { 51 | $it->next(); 52 | } 53 | } 54 | 55 | public function key() 56 | { 57 | return $this->it->key(); 58 | } 59 | 60 | public function current() 61 | { 62 | return $this->it->current(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Iterator/LazyFilterWithKeyIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->fn = $fn; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return 30 | new LazyFilterWithKeyIterator($this->Enumerable->getIterator(), $this->fn); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Iterator/LazyFilterWithKeyIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 22 | $this->fn = $fn; 23 | } 24 | 25 | public function __clone() 26 | { 27 | $this->it = clone $this->it; 28 | } 29 | 30 | public function rewind() 31 | { 32 | $it = $this->it; 33 | $fn = $this->fn; 34 | $it->rewind(); 35 | while ($it->valid() && !$fn($it->key(), $it->current())) { 36 | $it->next(); 37 | } 38 | } 39 | 40 | public function valid() 41 | { 42 | return $this->it->valid(); 43 | } 44 | 45 | public function next() 46 | { 47 | $it = $this->it; 48 | $fn = $this->fn; 49 | $it->next(); 50 | while ($it->valid() && !$fn($it->key(), $it->current())) { 51 | $it->next(); 52 | } 53 | } 54 | 55 | public function key() 56 | { 57 | return $this->it->key(); 58 | } 59 | 60 | public function current() 61 | { 62 | return $this->it->current(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Iterator/LazyIterableTrait.php: -------------------------------------------------------------------------------- 1 | toArray(); 29 | } 30 | 31 | public function toVector() 32 | { 33 | return new Vector($this); 34 | } 35 | 36 | public function toImmVector() 37 | { 38 | return new ImmVector($this); 39 | } 40 | 41 | public function toSet() 42 | { 43 | return new Set($this); 44 | } 45 | 46 | public function toImmSet() 47 | { 48 | return new ImmSet($this); 49 | } 50 | 51 | public function lazy() 52 | { 53 | return $this; 54 | } 55 | 56 | public function values() 57 | { 58 | return new LazyValuesIterable($this); 59 | } 60 | 61 | public function map(callable $callback) 62 | { 63 | return new LazyMapIterable($this, $callback); 64 | } 65 | 66 | public function filter(callable $callback) 67 | { 68 | return new LazyFilterIterable($this, $callback); 69 | } 70 | 71 | public function zip($Enumerable) 72 | { 73 | if (is_array($Enumerable)) { 74 | $Enumerable = new ImmMap($Enumerable); 75 | } 76 | 77 | return new LazyZipIterable($this, $Enumerable); 78 | } 79 | 80 | public function take($size = 1) 81 | { 82 | return new LazyTakeIterable($this, $size); 83 | } 84 | 85 | public function takeWhile($fn) 86 | { 87 | return new LazyTakeWhileIterable($this, $fn); 88 | } 89 | 90 | public function skip($n) 91 | { 92 | return new LazySkipIterable($this, $n); 93 | } 94 | 95 | public function skipWhile($fn) 96 | { 97 | return new LazySkipWhileIterable($this, $fn); 98 | } 99 | 100 | public function slice($start, $len) 101 | { 102 | return new LazySliceIterable($this, $start, $len); 103 | } 104 | 105 | public function concat($Enumerable) 106 | { 107 | if (is_array($Enumerable)) { 108 | $Enumerable = new ImmMap($Enumerable); 109 | } 110 | 111 | return new LazyConcatIterable($this, $Enumerable); 112 | } 113 | 114 | public function first() 115 | { 116 | foreach ($this as $v) { 117 | return $v; 118 | } 119 | 120 | return null; 121 | } 122 | 123 | public function last() 124 | { 125 | $v = null; 126 | foreach ($this as $v) { 127 | } 128 | 129 | return $v; 130 | } 131 | 132 | /** 133 | * {@inheritDoc} 134 | * @return $this 135 | */ 136 | public function each(callable $callable) 137 | { 138 | foreach ($this as $v) { 139 | $callable($v); 140 | } 141 | 142 | return $this; 143 | } 144 | 145 | /** 146 | * {@inheritdoc} 147 | */ 148 | public function exists(callable $fn) 149 | { 150 | foreach ($this as $element) { 151 | if ($fn($element)) { 152 | return true; 153 | } 154 | } 155 | 156 | return false; 157 | } 158 | 159 | public function concatAll() 160 | { 161 | /** @var VectorInterface $results */ 162 | $results = new static(); 163 | $this->each(function ($subArray) use ($results) { 164 | foreach ($subArray as $item) { 165 | $results->add($item); 166 | } 167 | }); 168 | 169 | return $results; 170 | } 171 | 172 | /** 173 | * {@inheritDoc} 174 | * @return $this 175 | */ 176 | public function groupBy($callback) 177 | { 178 | $group = new Map(); 179 | foreach ($this as $value) { 180 | $key = $callback($value); 181 | if (!$group->containsKey($key)) { 182 | $element = $this instanceof VectorInterface ? new static([$value]) : new Vector([$value]); 183 | $group->add(new Pair($key, $element)); 184 | } else { 185 | $value = $group->get($key)->add($value); 186 | $group->set($key, $value); 187 | } 188 | } 189 | 190 | return $group; 191 | } 192 | 193 | /** 194 | * {@inheritDoc} 195 | * @return $this 196 | */ 197 | public function indexBy($callback) 198 | { 199 | $group = new Map(); 200 | foreach ($this as $value) { 201 | $key = $callback($value); 202 | $group->set($key, $value); 203 | } 204 | 205 | return $group; 206 | } 207 | 208 | /** 209 | * {@inheritdoc} 210 | */ 211 | public function reduce(callable $callback, $initial = null) 212 | { 213 | foreach ($this as $element) { 214 | $initial = $callback($initial, $element); 215 | } 216 | 217 | return $initial; 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/Iterator/LazyKeyedIterableTrait.php: -------------------------------------------------------------------------------- 1 | $v) { 20 | $arr[$k] = $v; 21 | } 22 | 23 | return $arr; 24 | } 25 | 26 | public function toValuesArray() 27 | { 28 | $arr = []; 29 | foreach ($this as $v) { 30 | $arr[] = $v; 31 | } 32 | 33 | return $arr; 34 | } 35 | 36 | public function toKeysArray() 37 | { 38 | $arr = []; 39 | foreach ($this as $k => $_) { 40 | $arr[] = $k; 41 | } 42 | 43 | return $arr; 44 | } 45 | 46 | public function toVector() 47 | { 48 | return new Vector($this); 49 | } 50 | 51 | public function toImmVector() 52 | { 53 | return new ImmVector($this); 54 | } 55 | 56 | public function toMap() 57 | { 58 | return new Map($this); 59 | } 60 | 61 | public function toImmMap() 62 | { 63 | return new ImmMap($this); 64 | } 65 | 66 | public function toSet() 67 | { 68 | return new Set($this); 69 | } 70 | 71 | public function toImmSet() 72 | { 73 | return new ImmSet($this); 74 | } 75 | 76 | public function lazy() 77 | { 78 | return $this; 79 | } 80 | 81 | public function values() 82 | { 83 | return new LazyValuesIterable($this); 84 | } 85 | 86 | public function keys() 87 | { 88 | return new LazyKeysIterable($this); 89 | } 90 | 91 | public function map(callable $callback) 92 | { 93 | return new LazyMapKeyedIterable($this, $callback); 94 | } 95 | 96 | public function mapWithKey($callback) 97 | { 98 | return new LazyMapWithKeyIterable($this, $callback); 99 | } 100 | 101 | public function filter(callable $callback) 102 | { 103 | return new LazyFilterKeyedIterable($this, $callback); 104 | } 105 | 106 | public function filterWithKey($callback) 107 | { 108 | return new LazyFilterWithKeyIterable($this, $callback); 109 | } 110 | 111 | public function zip($traversable) 112 | { 113 | if (is_array($traversable)) { 114 | $traversable = new ImmMap($traversable); 115 | } 116 | 117 | return new LazyZipKeyedIterable($this, $traversable); 118 | } 119 | 120 | public function take($size = 1) 121 | { 122 | return new LazyTakeKeyedIterable($this, $size); 123 | } 124 | 125 | public function takeWhile($fn) 126 | { 127 | return new LazyTakeWhileKeyedIterable($this, $fn); 128 | } 129 | 130 | public function skip($n) 131 | { 132 | return new LazySkipKeyedIterable($this, $n); 133 | } 134 | 135 | public function skipWhile($fn) 136 | { 137 | return new LazySkipWhileKeyedIterable($this, $fn); 138 | } 139 | 140 | public function slice($start, $len) 141 | { 142 | return new LazySliceKeyedIterable($this, $start, $len); 143 | } 144 | 145 | public function concat($Enumerable) 146 | { 147 | if (is_array($Enumerable)) { 148 | $Enumerable = new ImmMap($Enumerable); 149 | } 150 | 151 | return new LazyConcatIterable($this, $Enumerable); 152 | } 153 | 154 | public function first() 155 | { 156 | foreach ($this as $v) { 157 | return $v; 158 | } 159 | 160 | return null; 161 | } 162 | 163 | public function firstKey() 164 | { 165 | foreach ($this as $k => $_) { 166 | return $k; 167 | } 168 | 169 | return null; 170 | } 171 | 172 | public function last() 173 | { 174 | $v = null; 175 | foreach ($this as $v) { 176 | } 177 | 178 | return $v; 179 | } 180 | 181 | public function lastKey() 182 | { 183 | $k = null; 184 | foreach ($this as $k => $_) { 185 | } 186 | 187 | return $k; 188 | } 189 | 190 | /** 191 | * {@inheritDoc} 192 | * @return $this 193 | */ 194 | public function each(callable $callable) 195 | { 196 | foreach ($this as $v) { 197 | $callable($v); 198 | } 199 | 200 | return $this; 201 | } 202 | 203 | /** 204 | * {@inheritdoc} 205 | */ 206 | public function exists(callable $fn) 207 | { 208 | foreach ($this as $element) { 209 | if ($fn($element)) { 210 | return true; 211 | } 212 | } 213 | 214 | return false; 215 | } 216 | 217 | public function concatAll() 218 | { 219 | /** @var VectorInterface $results */ 220 | $results = new static(); 221 | $this->each(function ($subArray) use ($results) { 222 | foreach ($subArray as $item) { 223 | $results->add($item); 224 | } 225 | }); 226 | 227 | return $results; 228 | } 229 | 230 | /** 231 | * {@inheritDoc} 232 | * @return $this 233 | */ 234 | public function groupBy($callback) 235 | { 236 | $group = new Map(); 237 | foreach ($this as $value) { 238 | $key = $callback($value); 239 | if (!$group->containsKey($key)) { 240 | $element = $this instanceof VectorInterface ? new static([$value]) : new Vector([$value]); 241 | $group->add(new Pair($key, $element)); 242 | } else { 243 | $value = $group->get($key)->add($value); 244 | $group->set($key, $value); 245 | } 246 | } 247 | 248 | return $group; 249 | } 250 | 251 | /** 252 | * {@inheritDoc} 253 | * @return $this 254 | */ 255 | public function indexBy($callback) 256 | { 257 | $group = new Map(); 258 | foreach ($this as $value) { 259 | $key = $callback($value); 260 | $group->set($key, $value); 261 | } 262 | 263 | return $group; 264 | } 265 | 266 | /** 267 | * {@inheritdoc} 268 | */ 269 | public function reduce(callable $callback, $initial = null) 270 | { 271 | foreach ($this as $element) { 272 | $initial = $callback($initial, $element); 273 | } 274 | 275 | return $initial; 276 | } 277 | } 278 | -------------------------------------------------------------------------------- /src/Iterator/LazyKeysIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 19 | } 20 | 21 | public function getIterator() 22 | { 23 | return new LazyKeysIterator($this->Enumerable->getIterator()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Iterator/LazyKeysIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 15 | } 16 | 17 | public function __clone() 18 | { 19 | $this->it = clone $this->it; 20 | } 21 | 22 | public function rewind() 23 | { 24 | $this->it->rewind(); 25 | } 26 | 27 | public function valid() 28 | { 29 | return $this->it->valid(); 30 | } 31 | 32 | public function next() 33 | { 34 | $this->it->next(); 35 | } 36 | 37 | public function key() 38 | { 39 | return null; 40 | } 41 | 42 | public function current() 43 | { 44 | return $this->it->key(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Iterator/LazyMapIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->fn = $fn; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazyMapIterator($this->Enumerable->getIterator(), $this->fn); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Iterator/LazyMapIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 20 | $this->fn = $fn; 21 | } 22 | 23 | public function __clone() 24 | { 25 | $this->it = clone $this->it; 26 | } 27 | 28 | public function rewind() 29 | { 30 | $this->it->rewind(); 31 | } 32 | 33 | public function valid() 34 | { 35 | return $this->it->valid(); 36 | } 37 | 38 | public function next() 39 | { 40 | $this->it->next(); 41 | } 42 | 43 | public function key() 44 | { 45 | return $this->it->key(); 46 | } 47 | 48 | public function current() 49 | { 50 | $fn = $this->fn; 51 | 52 | return $fn($this->it->current()); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Iterator/LazyMapKeyedIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->fn = $fn; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazyMapKeyedIterator($this->Enumerable->getIterator(), $this->fn); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/Iterator/LazyMapKeyedIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 22 | $this->fn = $fn; 23 | } 24 | 25 | public function __clone() 26 | { 27 | $this->it = clone $this->it; 28 | } 29 | 30 | public function rewind() 31 | { 32 | $this->it->rewind(); 33 | } 34 | 35 | public function valid() 36 | { 37 | return $this->it->valid(); 38 | } 39 | 40 | public function next() 41 | { 42 | $this->it->next(); 43 | } 44 | 45 | public function key() 46 | { 47 | return $this->it->key(); 48 | } 49 | 50 | public function current() 51 | { 52 | $fn = $this->fn; 53 | 54 | return $fn($this->it->current()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Iterator/LazyMapWithKeyIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->fn = $fn; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazyMapWithKeyIterator($this->Enumerable->getIterator(), $this->fn); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/Iterator/LazyMapWithKeyIterator.php: -------------------------------------------------------------------------------- 1 | fn; 10 | 11 | return $fn($this->it->key(), $this->it->current()); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Iterator/LazySkipIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 25 | $this->n = $n; 26 | } 27 | 28 | public function getIterator() 29 | { 30 | return new LazySkipIterator($this->Enumerable->getIterator(), $this->n); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/Iterator/LazySkipIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 20 | $this->n = $n; 21 | while ($n > 0 && $it->valid()) { 22 | $it->next(); 23 | --$n; 24 | } 25 | } 26 | 27 | public function __clone() 28 | { 29 | $this->it = clone $this->it; 30 | } 31 | 32 | public function rewind() 33 | { 34 | $it = $this->it; 35 | $n = $this->n; 36 | $it->rewind(); 37 | while ($n > 0 && $it->valid()) { 38 | $it->next(); 39 | --$n; 40 | } 41 | } 42 | 43 | public function valid() 44 | { 45 | return $this->it->valid(); 46 | } 47 | 48 | public function next() 49 | { 50 | $this->it->next(); 51 | } 52 | 53 | public function key() 54 | { 55 | return $this->it->key(); 56 | } 57 | 58 | public function current() 59 | { 60 | return $this->it->current(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Iterator/LazySkipKeyedIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->n = $n; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazySkipKeyedIterator($this->Enumerable->getIterator(), $this->n); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Iterator/LazySkipKeyedIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 22 | $this->n = $n; 23 | while ($n > 0 && $it->valid()) { 24 | $it->next(); 25 | --$n; 26 | } 27 | } 28 | 29 | public function __clone() 30 | { 31 | $this->it = clone $this->it; 32 | } 33 | 34 | public function rewind() 35 | { 36 | $it = $this->it; 37 | $n = $this->n; 38 | $it->rewind(); 39 | while ($n > 0 && $it->valid()) { 40 | $it->next(); 41 | --$n; 42 | } 43 | } 44 | 45 | public function valid() 46 | { 47 | return $this->it->valid(); 48 | } 49 | 50 | public function next() 51 | { 52 | $this->it->next(); 53 | } 54 | 55 | public function key() 56 | { 57 | return $this->it->key(); 58 | } 59 | 60 | public function current() 61 | { 62 | return $this->it->current(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Iterator/LazySkipWhileIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->fn = $fn; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazySkipWhileIterator($this->Enumerable->getIterator(), 30 | $this->fn); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Iterator/LazySkipWhileIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 20 | $this->fn = $fn; 21 | while ($it->valid() && $fn($it->current())) { 22 | $it->next(); 23 | } 24 | } 25 | 26 | public function __clone() 27 | { 28 | $this->it = clone $this->it; 29 | } 30 | 31 | public function rewind() 32 | { 33 | $it = $this->it; 34 | $fn = $this->fn; 35 | $it->rewind(); 36 | while ($it->valid() && $fn($it->current())) { 37 | $it->next(); 38 | } 39 | } 40 | 41 | public function valid() 42 | { 43 | return $this->it->valid(); 44 | } 45 | 46 | public function next() 47 | { 48 | $this->it->next(); 49 | } 50 | 51 | public function key() 52 | { 53 | return $this->it->key(); 54 | } 55 | 56 | public function current() 57 | { 58 | return $this->it->current(); 59 | } 60 | } -------------------------------------------------------------------------------- /src/Iterator/LazySkipWhileKeyedIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->fn = $fn; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazySkipWhileKeyedIterator($this->Enumerable->getIterator(), $this->fn); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Iterator/LazySkipWhileKeyedIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 20 | $this->fn = $fn; 21 | while ($it->valid() && $fn($it->current())) { 22 | $it->next(); 23 | } 24 | } 25 | 26 | public function __clone() 27 | { 28 | $this->it = clone $this->it; 29 | } 30 | 31 | public function rewind() 32 | { 33 | $it = $this->it; 34 | $fn = $this->fn; 35 | $it->rewind(); 36 | while ($it->valid() && $fn($it->current())) { 37 | $it->next(); 38 | } 39 | } 40 | 41 | public function valid() 42 | { 43 | return $this->it->valid(); 44 | } 45 | 46 | public function next() 47 | { 48 | $this->it->next(); 49 | } 50 | 51 | public function key() 52 | { 53 | return $this->it->key(); 54 | } 55 | 56 | public function current() 57 | { 58 | return $this->it->current(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Iterator/LazySliceIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 29 | $this->start = $start; 30 | $this->len = $len; 31 | } 32 | 33 | public function getIterator() 34 | { 35 | return new LazySliceIterator($this->Enumerable->getIterator(), $this->start, $this->len); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Iterator/LazySliceIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 30 | $this->start = $start; 31 | $this->len = $len; 32 | $this->currentLen = $len; 33 | while ($start !== 0 && $it->valid()) { 34 | $it->next(); 35 | --$start; 36 | } 37 | } 38 | 39 | public function __clone() 40 | { 41 | $this->it = clone $this->it; 42 | } 43 | 44 | public function rewind() 45 | { 46 | $it = $this->it; 47 | $start = $this->start; 48 | $len = $this->len; 49 | $it->rewind(); 50 | $this->currentLen = $len; 51 | while ($start !== 0 && $it->valid()) { 52 | $it->next(); 53 | --$start; 54 | } 55 | } 56 | 57 | public function valid() 58 | { 59 | return $this->it->valid() && $this->currentLen !== 0; 60 | } 61 | 62 | public function next() 63 | { 64 | $this->it->next(); 65 | if ($this->currentLen !== 0) { 66 | --$this->currentLen; 67 | } 68 | } 69 | 70 | public function key() 71 | { 72 | return $this->it->key(); 73 | } 74 | 75 | public function current() 76 | { 77 | return $this->it->current(); 78 | } 79 | } -------------------------------------------------------------------------------- /src/Iterator/LazySliceKeyedIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 29 | $this->start = $start; 30 | $this->len = $len; 31 | } 32 | 33 | public function getIterator() 34 | { 35 | return new LazySliceKeyedIterator($this->Enumerable->getIterator(), $this->start, $this->len); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Iterator/LazySliceKeyedIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 32 | $this->start = $start; 33 | $this->len = $len; 34 | $this->currentLen = $len; 35 | while ($start !== 0 && $it->valid()) { 36 | $it->next(); 37 | --$start; 38 | } 39 | } 40 | 41 | public function __clone() 42 | { 43 | $this->it = clone $this->it; 44 | } 45 | 46 | public function rewind() 47 | { 48 | $it = $this->it; 49 | $start = $this->start; 50 | $len = $this->len; 51 | $it->rewind(); 52 | $this->currentLen = $len; 53 | while ($start !== 0 && $it->valid()) { 54 | $it->next(); 55 | --$start; 56 | } 57 | } 58 | 59 | public function valid() 60 | { 61 | return $this->it->valid() && $this->currentLen !== 0; 62 | } 63 | 64 | public function next() 65 | { 66 | $this->it->next(); 67 | if ($this->currentLen !== 0) { 68 | --$this->currentLen; 69 | } 70 | } 71 | 72 | public function key() 73 | { 74 | return $this->it->key(); 75 | } 76 | 77 | public function current() 78 | { 79 | return $this->it->current(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/Iterator/LazyTakeIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->n = $n; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazyTakeIterator($this->Enumerable->getIterator(), $this->n); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /src/Iterator/LazyTakeIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 25 | $this->n = $n; 26 | $this->numLeft = $n; 27 | } 28 | 29 | public function __clone() 30 | { 31 | $this->it = clone $this->it; 32 | } 33 | 34 | public function rewind() 35 | { 36 | $this->it->rewind(); 37 | $this->numLeft = $this->n; 38 | } 39 | 40 | public function valid() 41 | { 42 | return ($this->numLeft > 0 && $this->it->valid()); 43 | } 44 | 45 | public function next() 46 | { 47 | $this->it->next(); 48 | --$this->numLeft; 49 | } 50 | 51 | public function key() 52 | { 53 | return $this->it->key(); 54 | } 55 | 56 | public function current() 57 | { 58 | return $this->it->current(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Iterator/LazyTakeKeyedIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->n = $n; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazyTakeKeyedIterator($this->Enumerable->getIterator(), $this->n); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Iterator/LazyTakeKeyedIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 27 | $this->n = $n; 28 | $this->numLeft = $n; 29 | } 30 | 31 | public function __clone() 32 | { 33 | $this->it = clone $this->it; 34 | } 35 | 36 | public function rewind() 37 | { 38 | $this->it->rewind(); 39 | $this->numLeft = $this->n; 40 | } 41 | 42 | public function valid() 43 | { 44 | return ($this->numLeft > 0 && $this->it->valid()); 45 | } 46 | 47 | public function next() 48 | { 49 | $this->it->next(); 50 | --$this->numLeft; 51 | } 52 | 53 | public function key() 54 | { 55 | return $this->it->key(); 56 | } 57 | 58 | public function current() 59 | { 60 | return $this->it->current(); 61 | } 62 | } -------------------------------------------------------------------------------- /src/Iterator/LazyTakeWhileIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 25 | $this->fn = $fn; 26 | } 27 | 28 | public function getIterator() 29 | { 30 | return new LazyTakeWhileIterator($this->Enumerable->getIterator(), $this->fn); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Iterator/LazyTakeWhileIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 20 | $this->fn = $fn; 21 | while ($it->valid() && $fn($it->current())) { 22 | $it->next(); 23 | } 24 | } 25 | 26 | public function __clone() 27 | { 28 | $this->it = clone $this->it; 29 | } 30 | 31 | public function rewind() 32 | { 33 | $this->it->rewind(); 34 | } 35 | 36 | public function valid() 37 | { 38 | $it = $this->it; 39 | $fn = $this->fn; 40 | 41 | return ($it->valid() && $fn($it->current())); 42 | } 43 | 44 | public function next() 45 | { 46 | $this->it->next(); 47 | } 48 | 49 | public function key() 50 | { 51 | return $this->it->key(); 52 | } 53 | 54 | public function current() 55 | { 56 | return $this->it->current(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Iterator/LazyTakeWhileKeyedIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 24 | $this->fn = $fn; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazyTakeWhileKeyedIterator($this->Enumerable->getIterator(), $this->fn); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Iterator/LazyTakeWhileKeyedIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 20 | $this->fn = $fn; 21 | } 22 | 23 | public function __clone() 24 | { 25 | $this->it = clone $this->it; 26 | } 27 | 28 | public function rewind() 29 | { 30 | $this->it->rewind(); 31 | } 32 | 33 | public function valid() 34 | { 35 | $it = $this->it; 36 | $fn = $this->fn; 37 | 38 | return ($it->valid() && $fn($it->current())); 39 | } 40 | 41 | public function next() 42 | { 43 | $this->it->next(); 44 | } 45 | 46 | public function key() 47 | { 48 | return $this->it->key(); 49 | } 50 | 51 | public function current() 52 | { 53 | return $this->it->current(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/Iterator/LazyValuesIterable.php: -------------------------------------------------------------------------------- 1 | Enumerable = $Enumerable; 19 | } 20 | 21 | public function getIterator() 22 | { 23 | return new LazyValuesIterator($this->Enumerable->getIterator()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Iterator/LazyValuesIterator.php: -------------------------------------------------------------------------------- 1 | it = $it; 15 | } 16 | 17 | public function __clone() 18 | { 19 | $this->it = clone $this->it; 20 | } 21 | 22 | public function rewind() 23 | { 24 | $this->it->rewind(); 25 | } 26 | 27 | public function valid() 28 | { 29 | return $this->it->valid(); 30 | } 31 | 32 | public function next() 33 | { 34 | $this->it->next(); 35 | } 36 | 37 | public function key() 38 | { 39 | return null; 40 | } 41 | 42 | public function current() 43 | { 44 | return $this->it->current(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Iterator/LazyZipIterable.php: -------------------------------------------------------------------------------- 1 | iterable1 = $iterable1; 24 | $this->iterable2 = $iterable2; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazyZipIterator($this->iterable1->getIterator(), $this->iterable2->getIterator()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Iterator/LazyZipIterator.php: -------------------------------------------------------------------------------- 1 | it1 = $it1; 22 | $this->it2 = $it2; 23 | } 24 | 25 | public function __clone() 26 | { 27 | $this->it1 = clone $this->it1; 28 | $this->it2 = clone $this->it2; 29 | } 30 | 31 | public function rewind() 32 | { 33 | $this->it1->rewind(); 34 | $this->it2->rewind(); 35 | } 36 | 37 | public function valid() 38 | { 39 | return ($this->it1->valid() && $this->it2->valid()); 40 | } 41 | 42 | public function next() 43 | { 44 | $this->it1->next(); 45 | $this->it2->next(); 46 | } 47 | 48 | public function key() 49 | { 50 | return $this->it1->key(); 51 | } 52 | 53 | public function current() 54 | { 55 | return new Pair($this->it1->current(), $this->it2->current()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Iterator/LazyZipKeyedIterable.php: -------------------------------------------------------------------------------- 1 | iterable1 = $iterable1; 24 | $this->iterable2 = $iterable2; 25 | } 26 | 27 | public function getIterator() 28 | { 29 | return new LazyZipKeyedIterator($this->iterable1->getIterator(), $this->iterable2->getIterator()); 30 | } 31 | } -------------------------------------------------------------------------------- /src/Iterator/LazyZipKeyedIterator.php: -------------------------------------------------------------------------------- 1 | it1 = $it1; 23 | $this->it2 = $it2; 24 | } 25 | 26 | public function __clone() 27 | { 28 | $this->it1 = clone $this->it1; 29 | $this->it2 = clone $this->it2; 30 | } 31 | 32 | public function rewind() 33 | { 34 | $this->it1->rewind(); 35 | $this->it2->rewind(); 36 | } 37 | 38 | public function valid() 39 | { 40 | return ($this->it1->valid() && $this->it2->valid()); 41 | } 42 | 43 | public function next() 44 | { 45 | $this->it1->next(); 46 | $this->it2->next(); 47 | } 48 | 49 | public function key() 50 | { 51 | return $this->it1->key(); 52 | } 53 | 54 | public function current() 55 | { 56 | return new Pair($this->it1->current(), $this->it2->current()); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Iterator/MapIterator.php: -------------------------------------------------------------------------------- 1 | init($array); 45 | } 46 | 47 | /** 48 | * Gets the collection's iterator 49 | * @return MapIterator 50 | */ 51 | public function getIterator() 52 | { 53 | return new MapIterator($this->container); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/MapAccessInterface.php: -------------------------------------------------------------------------------- 1 | container[] = $item1; 51 | $this->container[] = $item2; 52 | } 53 | 54 | /** 55 | * @inheritdoc 56 | */ 57 | public function getIterator() 58 | { 59 | return new PairIterator($this->container); 60 | } 61 | 62 | /** 63 | * Returns `false`; a `Pair` cannot be empty. 64 | * @return bool - `false` 65 | */ 66 | public function isEmpty() 67 | { 68 | return false; 69 | } 70 | 71 | /** 72 | * Returns 2; a `Pair` always has two values. 73 | * @return int 74 | */ 75 | public function count() 76 | { 77 | return 2; 78 | } 79 | 80 | /** 81 | * @internal 82 | */ 83 | public function __get($name) 84 | { 85 | throw InvalidOperationException::unsupportedGet($this); 86 | } 87 | 88 | /** 89 | * @internal 90 | */ 91 | public function __set($name, $value) 92 | { 93 | throw InvalidOperationException::unsupportedSet($this); 94 | } 95 | 96 | /** 97 | * @internal 98 | */ 99 | public function __isset($name) 100 | { 101 | return false; 102 | } 103 | 104 | /** 105 | * @internal 106 | */ 107 | public function __unset($name) 108 | { 109 | throw InvalidOperationException::unsupportedUnset($this); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/Queue.php: -------------------------------------------------------------------------------- 1 | enqueue($item); 22 | } 23 | 24 | return $this; 25 | } 26 | 27 | public static function fromArray(array $arr) 28 | { 29 | $collection = new Queue(); 30 | foreach ($arr as $v) { 31 | if (is_array($v)) { 32 | $collection->enqueue(static::fromArray($v)); 33 | } else { 34 | $collection->enqueue($v); 35 | } 36 | } 37 | 38 | return $collection; 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | public function toArray() 45 | { 46 | $array = array(); 47 | foreach ($this as $key => $value) { 48 | if ($value instanceof Enumerable) { 49 | $array[$key] = $value->toArray(); 50 | } else { 51 | $array[$key] = $value; 52 | } 53 | } 54 | 55 | return $array; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function __toString() 62 | { 63 | return get_class($this); 64 | } 65 | 66 | /** 67 | * (PHP 5 >= 5.4.0)
68 | * Specify data which should be serialized to JSON 69 | * @link http://php.net/manual/en/jsonserializable.jsonserialize.php 70 | * @return mixed data which can be serialized by json_encode, 71 | * which is a value of any type other than a resource. 72 | */ 73 | public function jsonSerialize() 74 | { 75 | return $this->toArray(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/QueueInterface.php: -------------------------------------------------------------------------------- 1 | init($array); 40 | } 41 | 42 | /** 43 | * @inheritDoc 44 | */ 45 | public function getIterator() 46 | { 47 | return new SetIterator($this->container); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/SetAccessInterface.php: -------------------------------------------------------------------------------- 1 | using the specified comparer. 16 | * @param ComparerInterface $comparer The ComparerInterface implementation to use when comparing elements, or null 17 | * to use the default comparer Comparer.Default. 18 | * @return $this 19 | */ 20 | public function sort(ComparerInterface $comparer = null) 21 | { 22 | if ($comparer === null) { 23 | $comparer = $this->getDefaultComparer(); 24 | } 25 | usort($this->container, array($comparer, 'compare')); 26 | 27 | return $this; 28 | } 29 | 30 | /** 31 | * Sorts the keys in the entire Collection using the specified comparer. 32 | * @param ComparerInterface $comparer The ComparerInterface implementation to use when comparing elements, or 33 | * null to use the default comparer Comparer.Default. 34 | * @return $this 35 | */ 36 | public function sortByKey(ComparerInterface $comparer = null) 37 | { 38 | if ($comparer === null) { 39 | $comparer = $this->getDefaultComparer(); 40 | } 41 | uksort($this->container, array($comparer, 'compare')); 42 | 43 | return $this; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Stack.php: -------------------------------------------------------------------------------- 1 | can be null. 16 | * @return $this|Stack 17 | */ 18 | public function pushMultiple($items) 19 | { 20 | foreach ($items as $item) { 21 | $this->push($item); 22 | } 23 | 24 | return $this; 25 | } 26 | 27 | public static function fromArray(array $arr) 28 | { 29 | $collection = new Stack(); 30 | foreach ($arr as $v) { 31 | if (is_array($v)) { 32 | $collection->push(static::fromArray($v)); 33 | } else { 34 | $collection->push($v); 35 | } 36 | } 37 | 38 | return $collection; 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | public function toArray() 45 | { 46 | $array = array(); 47 | foreach ($this as $key => $value) { 48 | if ($value instanceof Enumerable) { 49 | $array[$key] = $value->toArray(); 50 | } else { 51 | $array[$key] = $value; 52 | } 53 | } 54 | 55 | return $array; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function __toString() 62 | { 63 | return get_class($this); 64 | } 65 | 66 | /** 67 | * (PHP 5 >= 5.4.0)
68 | * Specify data which should be serialized to JSON 69 | * @link http://php.net/manual/en/jsonserializable.jsonserialize.php 70 | * @return mixed data which can be serialized by json_encode, 71 | * which is a value of any type other than a resource. 72 | */ 73 | public function jsonSerialize() 74 | { 75 | return $this->toArray(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/StackInterface.php: -------------------------------------------------------------------------------- 1 | can be null. 18 | * @return Stack 19 | */ 20 | public function push($item); 21 | 22 | /** 23 | * Inserts multiples objects at the top of the Stack. 24 | * @param CollectionInterface|array $items The Objects to push onto the Stack. The value can be null. 25 | * @return Stack 26 | */ 27 | public function pushMultiple($items); 28 | 29 | /** 30 | * Removes and returns the object at the top of the Stack. 31 | * @return mixed The Object removed from the top of the Stack. 32 | * @throws BadFunctionCallException 33 | */ 34 | public function pop(); 35 | } 36 | -------------------------------------------------------------------------------- /src/Traits/CommonContainerMethodsTrait.php: -------------------------------------------------------------------------------- 1 | defaultComparer === null) { 42 | $this->defaultComparer = new NumericKeyComparer(); 43 | } 44 | 45 | return $this->defaultComparer; 46 | } 47 | 48 | /** 49 | * Sets the default comparer for this collection 50 | * @param ComparerInterface $defaultComparer 51 | * @return $this 52 | */ 53 | public function setDefaultComparer(ComparerInterface $defaultComparer) 54 | { 55 | $this->defaultComparer = $defaultComparer; 56 | 57 | return $this; 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | public function __toString() 64 | { 65 | return get_class($this); 66 | } 67 | 68 | public function equals($obj) 69 | { 70 | return ($obj === $this); 71 | } 72 | 73 | /** 74 | * {@inheritdoc} 75 | */ 76 | public function serialize() 77 | { 78 | return serialize($this->container); 79 | } 80 | 81 | /** 82 | * {@inheritdoc} 83 | */ 84 | public function unserialize($serialized) 85 | { 86 | $this->container = unserialize($serialized); 87 | 88 | return $this->container; 89 | } 90 | 91 | /** 92 | * {@inheritdoc} 93 | */ 94 | public function jsonSerialize() 95 | { 96 | return $this->container; 97 | } 98 | 99 | /** 100 | * @return array 101 | */ 102 | public function toValuesArray() 103 | { 104 | $arr = []; 105 | foreach ($this as $value) { 106 | if ($value instanceof Enumerable) { 107 | $arr[] = $value->toArray(); 108 | } else { 109 | $arr[] = $value; 110 | } 111 | } 112 | 113 | return $arr; 114 | } 115 | 116 | public function toKeysArray() 117 | { 118 | $res = []; 119 | foreach ($this as $k => $_) { 120 | $res[] = $k; 121 | } 122 | 123 | return $res; 124 | } 125 | 126 | /** 127 | * {@inheritdoc} 128 | */ 129 | public function toArray() 130 | { 131 | $arr = []; 132 | foreach ($this as $key => $value) { 133 | if ($value instanceof Enumerable) { 134 | $arr[$key] = $value->toArray(); 135 | } else { 136 | $arr[$key] = $value; 137 | } 138 | } 139 | 140 | return $arr; 141 | } 142 | 143 | /** 144 | * {@inheritdoc} 145 | */ 146 | public static function fromArray(array $arr) 147 | { 148 | $map = new static(); 149 | foreach ($arr as $k => $v) { 150 | if (is_array($v)) { 151 | $map[$k] = new static($v); 152 | } else { 153 | $map[$k] = $v; 154 | } 155 | } 156 | 157 | return $map; 158 | } 159 | 160 | /** 161 | * {@inheritdoc} 162 | */ 163 | public function toVector() 164 | { 165 | return new Vector($this); 166 | } 167 | 168 | /** 169 | * {@inheritdoc} 170 | */ 171 | public function toImmVector() 172 | { 173 | return new ImmVector($this); 174 | } 175 | 176 | /** 177 | * {@inheritdoc} 178 | */ 179 | public function toSet() 180 | { 181 | return new Set($this); 182 | } 183 | 184 | /** 185 | * {@inheritdoc} 186 | */ 187 | public function toImmSet() 188 | { 189 | return new ImmSet($this); 190 | } 191 | 192 | /** 193 | * {@inheritdoc} 194 | */ 195 | public function toMap() 196 | { 197 | return new Map($this); 198 | } 199 | 200 | /** 201 | * {@inheritdoc} 202 | */ 203 | public function toImmMap() 204 | { 205 | return new ImmMap($this); 206 | } 207 | 208 | /** 209 | * {@inheritDoc} 210 | * @return $this 211 | */ 212 | public function map(callable $callable) 213 | { 214 | return new static(new LazyMapIterable($this, $callable)); 215 | } 216 | 217 | /** 218 | * {@inheritDoc} 219 | * @return $this 220 | */ 221 | public function mapWithKey($callback) 222 | { 223 | return new static(new LazyMapWithKeyIterable($this, $callback)); 224 | } 225 | 226 | /** 227 | * {@inheritDoc} 228 | * @return $this 229 | */ 230 | public function filter(callable $callable) 231 | { 232 | return new static(new LazyFilterIterable($this, $callable)); 233 | } 234 | 235 | /** 236 | * {@inheritDoc} 237 | * @return $this 238 | */ 239 | public function filterWithKey($callback) 240 | { 241 | return new static(new LazyFilterKeyedIterable($this, $callback)); 242 | } 243 | 244 | /** 245 | * {@inheritDoc} 246 | * @return $this 247 | */ 248 | public function zip($traversable) 249 | { 250 | if (is_array($traversable)) { 251 | $traversable = new ImmVector($traversable); 252 | } 253 | 254 | if ($traversable instanceof \Traversable) { 255 | return new static(new LazyZipIterable($this, $traversable)); 256 | } else { 257 | throw new \InvalidArgumentException('Parameter must be an array or an instance of Traversable'); 258 | } 259 | } 260 | 261 | /** 262 | * {@inheritDoc} 263 | * @return $this 264 | */ 265 | public function take($size = 1) 266 | { 267 | if (!is_int($size)) { 268 | throw new \InvalidArgumentException('Parameter n must be an integer'); 269 | } 270 | 271 | return new static(new LazyTakeIterable($this, $size)); 272 | } 273 | 274 | public function takeWhile(callable $callable) 275 | { 276 | return new static(new LazyTakeWhileIterable($this, $callable)); 277 | } 278 | 279 | public function skip($n) 280 | { 281 | if (!is_int($n)) { 282 | throw new \InvalidArgumentException('Parameter n must be an integer'); 283 | } 284 | 285 | return new static(new LazySkipIterable($this, $n)); 286 | } 287 | 288 | public function skipWhile(callable $callable) 289 | { 290 | return new static(new LazySkipWhileIterable($this, $callable)); 291 | } 292 | 293 | public function slice($start, $length) 294 | { 295 | if ($start < 0) { 296 | throw new \InvalidArgumentException('Parameter start must be a non-negative integer'); 297 | } 298 | if ($length < 0) { 299 | throw new \InvalidArgumentException('Parameter len must be a non-negative integer'); 300 | } 301 | 302 | return new static(new LazySliceIterable($this, $start, $length)); 303 | } 304 | 305 | /** 306 | * {@inheritDoc} 307 | * @return $this 308 | */ 309 | public function first() 310 | { 311 | if ($this->isEmpty()) { 312 | return null; 313 | } 314 | 315 | return current($this->container); 316 | } 317 | 318 | /** 319 | * {@inheritDoc} 320 | * @return $this 321 | */ 322 | public function last() 323 | { 324 | if ($this->isEmpty()) { 325 | return null; 326 | } 327 | 328 | $lastItem = array_slice($this->container, -1, 1); 329 | 330 | return current($lastItem); 331 | } 332 | 333 | /** 334 | * {@inheritdoc} 335 | */ 336 | public function exists(callable $fn) 337 | { 338 | foreach ($this as $element) { 339 | if ($fn($element)) { 340 | return true; 341 | } 342 | } 343 | 344 | return false; 345 | } 346 | 347 | public function concatAll() 348 | { 349 | /** @var VectorInterface $results */ 350 | $results = new static(); 351 | $this->each(function (Enumerable $subArray) use ($results) { 352 | $subArray->each(function ($item) use ($results) { 353 | $results->add($item); 354 | }); 355 | }); 356 | 357 | return $results; 358 | } 359 | 360 | /** 361 | * {@inheritDoc} 362 | * @return $this 363 | */ 364 | public function groupBy($callback) 365 | { 366 | $group = new Map(); 367 | foreach ($this as $value) { 368 | $key = $callback($value); 369 | if (!$group->containsKey($key)) { 370 | $element = $this instanceof VectorInterface ? new static([$value]) : new Vector([$value]); 371 | $group->add(new Pair($key, $element)); 372 | } else { 373 | $value = $group->get($key)->add($value); 374 | $group->set($key, $value); 375 | } 376 | } 377 | 378 | return $group; 379 | } 380 | 381 | /** 382 | * {@inheritDoc} 383 | * @return $this 384 | */ 385 | public function indexBy($callback) 386 | { 387 | $group = new Map(); 388 | foreach ($this as $value) { 389 | $key = $callback($value); 390 | $group->set($key, $value); 391 | } 392 | 393 | return $group; 394 | } 395 | 396 | /** 397 | * {@inheritdoc} 398 | */ 399 | public function reduce(callable $callback, $initial = null) 400 | { 401 | foreach ($this as $element) { 402 | $initial = $callback($initial, $element); 403 | } 404 | 405 | return $initial; 406 | } 407 | } 408 | -------------------------------------------------------------------------------- /src/Traits/CommonImmMutableContainerTrait.php: -------------------------------------------------------------------------------- 1 | toImmVector(); 17 | } 18 | 19 | public function keys() 20 | { 21 | return new ImmVector(new LazyKeysIterable($this)); 22 | } 23 | 24 | /** 25 | * {@inheritDoc} 26 | */ 27 | public function concat($Enumerable) 28 | { 29 | if (is_array($Enumerable)) { 30 | $Enumerable = new ImmVector($Enumerable); 31 | } 32 | 33 | if ($Enumerable instanceof \Traversable) { 34 | return new ImmVector(new LazyConcatIterator($this, $Enumerable)); 35 | } else { 36 | throw new \InvalidArgumentException('Parameter must be an array or an instance of Traversable'); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/Traits/CommonMutableContainerTrait.php: -------------------------------------------------------------------------------- 1 | validateTraversable($items); 19 | $isMap = $items instanceof MapInterface; 20 | 21 | foreach ($items as $key => $value) { 22 | if (is_array($value)) { 23 | $value = new static($value); 24 | } 25 | 26 | if ($isMap && !$value instanceof Pair) { 27 | $value = new Pair($key, $value); 28 | } 29 | 30 | $this->add($value); 31 | } 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public function values() 38 | { 39 | return new Vector($this); 40 | } 41 | 42 | public function keys() 43 | { 44 | return new Vector(new LazyKeysIterable($this)); 45 | } 46 | 47 | /** 48 | * {@inheritDoc} 49 | */ 50 | public function concat($Enumerable) 51 | { 52 | if ($Enumerable instanceof Enumerable) { 53 | $Enumerable = $Enumerable->toArray(); 54 | } 55 | 56 | return new static(array_merge_recursive($this->toArray(), $Enumerable)); 57 | } 58 | 59 | /** 60 | * {@inheritdoc} 61 | */ 62 | public function clear() 63 | { 64 | $old = $this->container; 65 | 66 | $this->container = []; 67 | 68 | unset($old); 69 | 70 | return $this; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Traits/ConstMapLikeTrait.php: -------------------------------------------------------------------------------- 1 | validateTraversable($it); 20 | 21 | $coll = []; 22 | foreach ($it as $key => $value) { 23 | if (is_array($value)) { 24 | $value = new static($value); 25 | } 26 | $coll[$key] = $value; 27 | } 28 | $this->container = $coll; 29 | } else { 30 | $this->container = []; 31 | } 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public function isEmpty() 38 | { 39 | return $this->count() === 0; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function count() 46 | { 47 | return count($this->container); 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function at($key) 54 | { 55 | $this->validateKeyDoesNotExists($key); 56 | 57 | return $this->container[$key]; 58 | } 59 | 60 | /** 61 | * {@inheritdoc} 62 | */ 63 | public function get($index) 64 | { 65 | if ($this->containsKey($index)) { 66 | return $this->container[$index]; 67 | } 68 | 69 | return null; 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | */ 75 | public function containsKey($key) 76 | { 77 | return array_key_exists($key, $this->container); 78 | } 79 | 80 | /** 81 | * {@inheritdoc} 82 | */ 83 | public function contains($element) 84 | { 85 | return in_array($element, $this->container, true); 86 | } 87 | 88 | 89 | /** 90 | * {@inheritdoc} 91 | */ 92 | public function offsetExists($offset) 93 | { 94 | return $this->containsKey($offset) && $this->at($offset) !== null; 95 | } 96 | 97 | /** 98 | * Returns an array containing the values from this VectorLike. 99 | */ 100 | public function toArray() 101 | { 102 | $arr = []; 103 | foreach ($this as $key => $value) { 104 | if ($value instanceof Enumerable) { 105 | $arr[$key] = $value->toArray(); 106 | } else { 107 | $arr[$key] = $value; 108 | } 109 | } 110 | 111 | return $arr; 112 | } 113 | 114 | /** 115 | * {@inheritDoc} 116 | * @return $this 117 | */ 118 | public function each(callable $callable) 119 | { 120 | foreach ($this as $k => $v) { 121 | $callable($v, $k); 122 | } 123 | 124 | return $this; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/Traits/ConstSetLikeTrait.php: -------------------------------------------------------------------------------- 1 | validateTraversable($it); 20 | 21 | $coll = []; 22 | foreach ($it as $value) { 23 | if (is_array($value)) { 24 | $value = new static($value); 25 | } 26 | $coll[] = $value; 27 | } 28 | $this->container = $coll; 29 | } else { 30 | $this->container = []; 31 | } 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public function isEmpty() 38 | { 39 | return $this->count() === 0; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function count() 46 | { 47 | return count($this->container); 48 | } 49 | 50 | /** 51 | * identical to at, implemented for ArrayAccess 52 | */ 53 | public function offsetGet($offset) 54 | { 55 | return $this->container[$offset]; 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function offsetExists($offset) 62 | { 63 | return $this->containsKey($offset); 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | public function containsKey($key) 70 | { 71 | return array_key_exists($key, $this->container); 72 | } 73 | 74 | /** 75 | * @inheritDoc 76 | */ 77 | public function contains($item) 78 | { 79 | return in_array($item, $this->container, true); 80 | } 81 | 82 | /** 83 | * Returns an array containing the values from this VectorLike. 84 | */ 85 | public function toArray() 86 | { 87 | $arr = []; 88 | foreach ($this as $k => $v) { 89 | if ($v instanceof Enumerable) { 90 | $arr[] = $v->toArray(); 91 | } else { 92 | $arr[] = $v; 93 | } 94 | } 95 | 96 | return $arr; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Traits/ConstVectorLikeTrait.php: -------------------------------------------------------------------------------- 1 | validateTraversable($it); 20 | 21 | $coll = []; 22 | foreach ($it as $value) { 23 | if (is_array($value)) { 24 | $value = new static($value); 25 | } 26 | $coll[] = $value; 27 | } 28 | $this->container = $coll; 29 | } else { 30 | $this->container = []; 31 | } 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public function isEmpty() 38 | { 39 | return $this->count() === 0; 40 | } 41 | 42 | /** 43 | * {@inheritdoc} 44 | */ 45 | public function count() 46 | { 47 | return count($this->container); 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function at($key) 54 | { 55 | $this->validateKeyType($key); 56 | $this->validateKeyBounds($key); 57 | 58 | return $this->container[$key]; 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | */ 64 | public function get($index) 65 | { 66 | $this->validateKeyType($index); 67 | 68 | return $this->container[$index]; 69 | } 70 | 71 | /** 72 | * {@inheritdoc} 73 | */ 74 | public function containsKey($key) 75 | { 76 | $this->validateKeyType($key); 77 | 78 | return $key >= 0 && $key < $this->count(); 79 | } 80 | 81 | /** 82 | * {@inheritdoc} 83 | */ 84 | public function offsetExists($offset) 85 | { 86 | return $this->containsKey($offset) && $this->at($offset) !== null; 87 | } 88 | 89 | /** 90 | * Returns an array containing the values from this VectorLike. 91 | */ 92 | public function toArray() 93 | { 94 | $arr = []; 95 | foreach ($this as $k => $v) { 96 | if ($v instanceof Enumerable) { 97 | $arr[] = $v->toArray(); 98 | } else { 99 | $arr[] = $v; 100 | } 101 | } 102 | 103 | return $arr; 104 | } 105 | 106 | /** 107 | * {@inheritDoc} 108 | * @return $this 109 | */ 110 | public function each(callable $callable) 111 | { 112 | foreach ($this as $v) { 113 | $callable($v); 114 | } 115 | 116 | return $this; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/Traits/GuardTrait.php: -------------------------------------------------------------------------------- 1 | isEmpty()) { 24 | throw new EmptyException("{$method} cannot be called when the structure is empty"); 25 | } 26 | } 27 | 28 | /** 29 | * Validates if a key is withing bounds (usually only useful with vectors) 30 | * @param $key 31 | */ 32 | protected function validateKeyBounds($key) 33 | { 34 | if (!$this->isBoundedKey($key)) { 35 | throw new \OutOfBoundsException("Integer key $key is out of bounds"); 36 | } 37 | } 38 | 39 | /** 40 | * @param $key 41 | */ 42 | protected function validateKeyDoesNotExists($key) 43 | { 44 | if (!$this->containsKey($key)) { 45 | throw new \OutOfBoundsException('No element at position ' . $key); 46 | } 47 | } 48 | 49 | /** 50 | * @param $key 51 | */ 52 | protected function validateKeyExists($key) 53 | { 54 | if ($this->containsKey($key)) { 55 | throw new KeyException('The key ' . $key . ' already exists!'); 56 | } 57 | } 58 | 59 | /** 60 | * @param int $element 61 | * @return bool 62 | */ 63 | protected function isBoundedKey($element) 64 | { 65 | return $element >= 0 && $element < $this->count(); 66 | } 67 | 68 | /** 69 | * Validate if an element respects the correct type (usually only useful with vectors) 70 | * @param $element 71 | * @throws TypeException 72 | */ 73 | protected function validateKeyType($element) 74 | { 75 | if (filter_var($element, FILTER_VALIDATE_INT) === false) { 76 | throw new TypeException('Only integer keys may be used with ' . (get_class($this))); 77 | } 78 | } 79 | 80 | protected function validateTraversable($traversable) 81 | { 82 | if (!is_array($traversable) && !$traversable instanceof \Traversable) { 83 | throw InvalidArgumentException::invalidTraversable(); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/Traits/ImmMapLikeTrait.php: -------------------------------------------------------------------------------- 1 | at($offset); 17 | } 18 | 19 | public function offsetSet($offset, $value) 20 | { 21 | throw InvalidOperationException::unsupportedSet($this); 22 | } 23 | 24 | public function offsetUnset($offset) 25 | { 26 | throw InvalidOperationException::unsupportedUnset($this); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Traits/ImmSetLikeTrait.php: -------------------------------------------------------------------------------- 1 | validateKeyType($offset); 17 | $this->validateKeyBounds($offset); 18 | 19 | return $this->container[$offset]; 20 | } 21 | 22 | public function offsetSet($offset, $value) 23 | { 24 | throw InvalidOperationException::unsupportedSet($this); 25 | } 26 | 27 | public function offsetUnset($offset) 28 | { 29 | throw InvalidOperationException::unsupportedUnset($this); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Traits/MapLikeTrait.php: -------------------------------------------------------------------------------- 1 | at($offset); 18 | } 19 | 20 | public function offsetSet($offset, $value) 21 | { 22 | if (is_null($offset)) { 23 | $this->add($value); 24 | } else { 25 | $this->set($offset, $value); 26 | } 27 | } 28 | 29 | public function offsetUnset($offset) 30 | { 31 | $this->removeKey($offset); 32 | } 33 | 34 | /** 35 | * {@inheritdoc} 36 | */ 37 | public function set($key, $value) 38 | { 39 | $this->container[$key] = $value; 40 | 41 | return $this; 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | public function setAll($items) 48 | { 49 | $this->validateTraversable($items); 50 | 51 | foreach ($items as $key => $item) { 52 | if (is_array($item)) { 53 | $item = new static($item); 54 | } 55 | $this->set($key, $item); 56 | } 57 | 58 | return $this; 59 | } 60 | 61 | /** 62 | * {@inheritdoc} 63 | */ 64 | public function add($pair) 65 | { 66 | if (!($pair instanceof Pair)) { 67 | throw new \InvalidArgumentException('Parameter must be an instance of Pair'); 68 | } 69 | 70 | list($key, $value) = $pair; 71 | 72 | $this->validateKeyExists($key); 73 | $this->set($key, $value); 74 | 75 | return $this; 76 | } 77 | 78 | /** 79 | * {@inheritdoc} 80 | */ 81 | public function removeKey($key) 82 | { 83 | $this->validateKeyDoesNotExists($key); 84 | 85 | unset($this->container[$key]); 86 | 87 | return $this; 88 | } 89 | 90 | /** 91 | * {@inheritdoc} 92 | */ 93 | public function remove($element) 94 | { 95 | $key = array_search($element, $this->container); 96 | 97 | if (false === $key) { 98 | throw new \OutOfBoundsException('No element found in the collection'); 99 | } 100 | 101 | $this->removeKey($key); 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * {@inheritDoc} 108 | * @return $this 109 | */ 110 | public function each(callable $callable) 111 | { 112 | foreach ($this as $k => $v) { 113 | $callable($v, $k); 114 | } 115 | 116 | return $this; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/Traits/SetLikeTrait.php: -------------------------------------------------------------------------------- 1 | add($value); 17 | } else { 18 | throw new InvalidOperationException('[] operator cannot be used to modify elements of a Set'); 19 | } 20 | } 21 | 22 | public function offsetUnset($offset) 23 | { 24 | $this->remove($offset); 25 | } 26 | 27 | /** 28 | * {@inheritdoc} 29 | */ 30 | public function add($item) 31 | { 32 | if ($this->contains($item)) { 33 | throw ElementAlreadyExists::duplicatedElement($item); 34 | } 35 | 36 | $this->container[] = $item; 37 | 38 | return $this; 39 | } 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | public function removeKey($key) 45 | { 46 | $this->validateKeyDoesNotExists($key); 47 | 48 | unset($this->container[$key]); 49 | 50 | return $this; 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | */ 56 | public function remove($element) 57 | { 58 | $key = array_search($element, $this->container); 59 | 60 | if (false === $key) { 61 | throw new \OutOfBoundsException('No element found in the collection'); 62 | } 63 | 64 | $this->removeKey($key); 65 | 66 | return $this; 67 | } 68 | 69 | /** 70 | * @inheritDoc 71 | */ 72 | public function removeAll($traversable) 73 | { 74 | foreach ($traversable as $item) { 75 | if ($this->contains($item)) { 76 | $this->remove($item); 77 | } 78 | } 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * {@inheritDoc} 85 | * @return $this 86 | */ 87 | public function each(callable $callable) 88 | { 89 | foreach ($this as $v) { 90 | $callable($v); 91 | } 92 | 93 | return $this; 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Traits/VectorLikeTrait.php: -------------------------------------------------------------------------------- 1 | at($offset); 18 | } 19 | 20 | public function offsetSet($offset, $value) 21 | { 22 | if (is_null($offset)) { 23 | $this->add($value); 24 | } else { 25 | $this->set($offset, $value); 26 | } 27 | } 28 | 29 | public function offsetUnset($offset) 30 | { 31 | throw InvalidOperationException::unsupportedUnset($this); 32 | } 33 | 34 | /** 35 | * Stores a value into the Vector with the specified key, overwriting the 36 | * previous value associated with the key. If the key is not present, 37 | * an exception is thrown. "$vec->set($k,$v)" is semantically equivalent 38 | * to "$vec[$k] = $v" (except that set() returns the Vector). 39 | * 40 | * @param $key 41 | * @param $value 42 | * @return $this 43 | */ 44 | public function set($key, $value) 45 | { 46 | $this->validateKeyType($key); 47 | $this->container[$key] = $value; 48 | 49 | return $this; 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function setAll($items) 56 | { 57 | $this->validateTraversable($items); 58 | 59 | foreach ($items as $key => $item) { 60 | if (is_array($item)) { 61 | $item = new static($item); 62 | } 63 | $this->set($key, $item); 64 | } 65 | 66 | return $this; 67 | } 68 | 69 | /** 70 | * {@inheritdoc} 71 | */ 72 | public function add($item) 73 | { 74 | $this->container[] = $item; 75 | 76 | return $this; 77 | } 78 | 79 | /** 80 | * {@inheritdoc} 81 | */ 82 | public function removeKey($key) 83 | { 84 | $this->validateKeyType($key); 85 | $this->validateKeyBounds($key); 86 | 87 | array_splice($this->container, $key, 1); 88 | 89 | return $this; 90 | } 91 | 92 | /** 93 | * {@inheritdoc} 94 | */ 95 | public function splice($offset, $length = null) 96 | { 97 | if (!is_int($offset)) { 98 | throw new \InvalidArgumentException('Parameter offset must be an integer'); 99 | } 100 | 101 | if (!is_null($length) && !is_int($length)) { 102 | throw new \InvalidArgumentException('Parameter len must be null or an integer'); 103 | } 104 | 105 | $removed = is_null($length) ? array_splice($this->container, $offset) : 106 | array_splice($this->container, $offset, $len); 107 | 108 | // if (count($removed) > 0) { 109 | // $this->hacklib_expireAllIterators(); 110 | // } 111 | } 112 | 113 | /** 114 | * {@inheritDoc} 115 | * @return $this 116 | */ 117 | public function each(callable $callable) 118 | { 119 | foreach ($this as $v) { 120 | $callable($v); 121 | } 122 | 123 | return $this; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/Vector.php: -------------------------------------------------------------------------------- 1 | init($array); 43 | } 44 | 45 | public static function fromItems($items) 46 | { 47 | return new self($items); 48 | } 49 | 50 | /** 51 | * {@inheritdoc} 52 | */ 53 | public function indexOf($item) 54 | { 55 | return array_search($item, $this->container, true); 56 | } 57 | 58 | /** 59 | * {@inheritdoc} 60 | */ 61 | public function reverse() 62 | { 63 | return static::fromArray(array_reverse($this->container)); 64 | } 65 | 66 | /** 67 | * Gets the collection's iterator 68 | * @return VectorIterator 69 | */ 70 | public function getIterator() 71 | { 72 | return new VectorIterator($this->container); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/VectorInterface.php: -------------------------------------------------------------------------------- 1 | assertJsonStringEqualsJsonString($serializedColl, $expectedSerialization); 23 | } 24 | 25 | /** 26 | * @test 27 | * @dataProvider collectionProvider 28 | * @param $coll 29 | */ 30 | public function is_should_php_serialize_it($coll) 31 | { 32 | $serializedColl = serialize($coll); 33 | $this->assertInternalType("string", $serializedColl); 34 | $collection = unserialize($serializedColl); 35 | $this->assertInstanceOf(get_class($coll), $collection); 36 | } 37 | 38 | public function collectionProvider() 39 | { 40 | $data = [1, 2, 3, 4]; 41 | 42 | $queue = new Queue(); 43 | $queue->push(1); 44 | 45 | $stack = new Stack(); 46 | $stack->push(1); 47 | 48 | return [ 49 | [new Vector($data), '[1,2,3,4]'], 50 | [new Set($data), '[1,2,3,4]'], 51 | [new Map(['test' => 'test']), '{"test": "test"}'], 52 | [$queue, '[1]'], 53 | [$stack, '[1]'], 54 | ]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /tests/CollectionsTestCase.php: -------------------------------------------------------------------------------- 1 | coll = $this->setUpCollection(); 40 | } 41 | 42 | /** 43 | * @test 44 | */ 45 | public function is_should_return_keys() 46 | { 47 | if ($this->coll instanceof MapInterface) { 48 | $this->coll->add(new Pair(0, 'value')); 49 | } else { 50 | $this->coll->add('value'); 51 | } 52 | 53 | $keys = $this->coll->keys(); 54 | 55 | $this->assertInstanceOf(VectorInterface::class, $keys); 56 | $this->assertEquals([0], $keys->toArray()); 57 | } 58 | 59 | /** 60 | * @test 61 | */ 62 | public function it_should_clear_the_collection() 63 | { 64 | if ($this->coll instanceof MapInterface) { 65 | $this->coll->add(new Pair(0, 'value')); 66 | } else { 67 | $this->coll->add('value'); 68 | } 69 | 70 | $this->coll->clear(); 71 | 72 | $this->assertTrue($this->coll->isEmpty()); 73 | } 74 | 75 | /** 76 | * @test 77 | */ 78 | public function is_should_concatenate_vectors() 79 | { 80 | if ($this->coll instanceof MapInterface) { 81 | $this->coll 82 | ->add(new Pair(0, 1)) 83 | ->add(new Pair(1, 2)) 84 | ->add(new Pair(3, 4)); 85 | } else { 86 | $this->coll 87 | ->add(1) 88 | ->add(2) 89 | ->add(4); 90 | } 91 | 92 | $coll2 = new Vector([3]); 93 | $concatenated = $this->coll->concat($coll2); 94 | 95 | $this->assertEquals([ 96 | 1, 97 | 2, 98 | 4, 99 | 3 100 | ], $concatenated->toArray()); 101 | } 102 | 103 | /** 104 | * @test 105 | */ 106 | public function is_should_concatenate_maps() 107 | { 108 | $coll3 = new Map([ 109 | 'key1' => 'value1', 110 | 'key2' => 'wrongValue', 111 | 'key3' => [ 112 | 'key31' => 'value31', 113 | ] 114 | ]); 115 | 116 | $coll4 = new Map([ 117 | 'key2' => 'value2', 118 | 'key3' => [ 119 | 'key32' => 'value32' 120 | ] 121 | ]); 122 | $concatenated = $coll3->concat($coll4); 123 | 124 | $this->assertEquals([ 125 | 'key1' => 'value1', 126 | 'key2' => [ 127 | 'wrongValue', 128 | 'value2' 129 | ], 130 | 'key3' => [ 131 | 'key31' => 'value31', 132 | 'key32' => 'value32' 133 | ] 134 | ], $concatenated->toArray()); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /tests/Comparer/NumericKeyComparerTest.php: -------------------------------------------------------------------------------- 1 | compare(3, 2); 16 | 17 | $this->assertInternalType("int", $result); 18 | } 19 | 20 | /** 21 | * @test 22 | */ 23 | public function first_is_less_than_second() 24 | { 25 | $comparer = new NumericKeyComparer(); 26 | $result = $comparer->compare(2,3); 27 | 28 | $this->assertSame($result,1); 29 | } 30 | 31 | /** 32 | * @test 33 | */ 34 | public function first_equals_second() 35 | { 36 | $comparer = new NumericKeyComparer(); 37 | $result = $comparer->compare(2,2); 38 | 39 | $this->assertSame($result,0); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/Comparer/StringComparerTest.php: -------------------------------------------------------------------------------- 1 | compare("test", "amazing"); 16 | 17 | $this->assertInternalType("int", $result); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/EnumerableTest.php: -------------------------------------------------------------------------------- 1 | coll->add('testing1'); 23 | $this->coll->add('testing2'); 24 | 25 | $values = $this->coll->values(); 26 | 27 | $this->assertInstanceOf(Vector::class, $values); 28 | $this->assertEquals(['testing1', 'testing2'], $values->toArray()); 29 | } 30 | 31 | /** 32 | * @test 33 | */ 34 | public function it_should_get_first_element() 35 | { 36 | $this->coll 37 | ->add("test1") 38 | ->add("test2") 39 | ->add("test3"); 40 | 41 | $this->assertSame("test1", $this->coll->first()); 42 | } 43 | 44 | /** 45 | * @test 46 | */ 47 | public function it_should_get_first_element_of_empty_collection() 48 | { 49 | $this->assertEmpty($this->coll->first()); 50 | } 51 | 52 | /** 53 | * @test 54 | */ 55 | public function it_should_get_last_element() 56 | { 57 | $this->coll 58 | ->add("test1") 59 | ->add("test2") 60 | ->add("test3"); 61 | 62 | $this->assertSame("test3", $this->coll->last()); 63 | } 64 | 65 | public function testGetLastElementOfEmptyCollection() 66 | { 67 | $this->assertEmpty($this->coll->last()); 68 | } 69 | 70 | /** 71 | * @test 72 | */ 73 | public function it_should_map() 74 | { 75 | $this->coll 76 | ->add(1) 77 | ->add(2) 78 | ->add(3); 79 | 80 | $coll = $this->coll->map(function ($item) { 81 | return $item * 2; 82 | }); 83 | 84 | $this->assertSame([ 85 | 2, 86 | 4, 87 | 6 88 | ], $coll->toArray()); 89 | } 90 | 91 | /** 92 | * @test 93 | */ 94 | public function it_should_map_with_keys() 95 | { 96 | $this->coll 97 | ->add(1) 98 | ->add(2) 99 | ->add(3); 100 | 101 | $coll = $this->coll->mapWithKey(function ($key, $item) { 102 | return $key; 103 | }); 104 | 105 | $this->assertSame([ 106 | 0, 107 | 1, 108 | 2 109 | ], $coll->toArray()); 110 | } 111 | 112 | /** 113 | * @test 114 | */ 115 | public function it_should_take_2_elements() 116 | { 117 | $this->coll 118 | ->add(1) 119 | ->add(2) 120 | ->add(3); 121 | 122 | $this->assertSame([ 123 | 1, 124 | 2 125 | ], $this->coll->take(2)->toArray()); 126 | } 127 | 128 | /** 129 | * @test 130 | * @dataProvider filterProvider 131 | */ 132 | public function it_should_filter_successfully(Enumerable $coll, $expected) 133 | { 134 | $coll = $coll->filter(function ($item) { 135 | return $item > 1; 136 | }); 137 | 138 | $this->assertEquals($expected, $coll->toArray()); 139 | } 140 | 141 | public function filterProvider() 142 | { 143 | return [ 144 | [new Map([0 => 1, 1 => 2, 2 => 3]), [1 => 2, 2 => 3]], 145 | [new Vector([1, 2, 3]), [2, 3]], 146 | [new Set([1, 2, 3]), [2, 3]] 147 | ]; 148 | } 149 | 150 | /** 151 | * @test 152 | */ 153 | public function it_should_group_by_callable() 154 | { 155 | $items = [ 156 | ['id' => 1, 'name' => 'foo', 'parent_id' => 10], 157 | ['id' => 2, 'name' => 'bar', 'parent_id' => 11], 158 | ['id' => 3, 'name' => 'baz', 'parent_id' => 10], 159 | ]; 160 | $collection = new Map($items); 161 | $grouped = $collection->groupBy(function ($item) { 162 | return $item['parent_id']; 163 | }); 164 | $expected = [ 165 | 10 => [ 166 | ['id' => 1, 'name' => 'foo', 'parent_id' => 10], 167 | ['id' => 3, 'name' => 'baz', 'parent_id' => 10], 168 | ], 169 | 11 => [ 170 | ['id' => 2, 'name' => 'bar', 'parent_id' => 11], 171 | ] 172 | ]; 173 | $this->assertEquals($expected, $grouped->toArray()); 174 | $this->assertInstanceOf('Collections\CollectionInterface', $grouped); 175 | $grouped = $collection->groupBy(function ($element) { 176 | return $element['parent_id']; 177 | }); 178 | $this->assertEquals($expected, $grouped->toArray()); 179 | } 180 | 181 | /** 182 | * @test 183 | */ 184 | public function it_should_group_by_key_deep() 185 | { 186 | $items = [ 187 | ['id' => 1, 'name' => 'foo', 'thing' => ['parent_id' => 10]], 188 | ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]], 189 | ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]], 190 | ]; 191 | $collection = new Map($items); 192 | $grouped = $collection->groupBy(function ($element) { 193 | return $element['thing']['parent_id']; 194 | }); 195 | $expected = [ 196 | 10 => [ 197 | ['id' => 1, 'name' => 'foo', 'thing' => ['parent_id' => 10]], 198 | ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]], 199 | ], 200 | 11 => [ 201 | ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]], 202 | ] 203 | ]; 204 | $this->assertEquals($expected, $grouped->toArray()); 205 | } 206 | 207 | /** 208 | * @test 209 | */ 210 | public function it_should_index_by_callable() 211 | { 212 | $items = [ 213 | ['id' => 1, 'name' => 'foo', 'parent_id' => 10], 214 | ['id' => 2, 'name' => 'bar', 'parent_id' => 11], 215 | ['id' => 3, 'name' => 'baz', 'parent_id' => 10], 216 | ]; 217 | $collection = new Map($items); 218 | $grouped = $collection->indexBy(function ($element) { 219 | return $element['id']; 220 | }); 221 | $expected = [ 222 | 1 => ['id' => 1, 'name' => 'foo', 'parent_id' => 10], 223 | 3 => ['id' => 3, 'name' => 'baz', 'parent_id' => 10], 224 | 2 => ['id' => 2, 'name' => 'bar', 'parent_id' => 11], 225 | ]; 226 | $this->assertEquals($expected, $grouped->toArray()); 227 | $this->assertInstanceOf('Collections\CollectionInterface', $grouped); 228 | $grouped = $collection->indexBy(function ($element) { 229 | return $element['id']; 230 | }); 231 | $this->assertEquals($expected, $grouped->toArray()); 232 | } 233 | 234 | /** 235 | * @test 236 | */ 237 | public function it_should_index_deep() 238 | { 239 | $items = [ 240 | ['id' => 1, 'name' => 'foo', 'thing' => ['parent_id' => 10]], 241 | ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]], 242 | ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]], 243 | ]; 244 | $collection = new Map($items); 245 | $grouped = $collection->indexBy(function ($element) { 246 | return $element['thing']['parent_id']; 247 | }); 248 | $expected = [ 249 | 10 => ['id' => 3, 'name' => 'baz', 'thing' => ['parent_id' => 10]], 250 | 11 => ['id' => 2, 'name' => 'bar', 'thing' => ['parent_id' => 11]], 251 | ]; 252 | $this->assertEquals($expected, $grouped->toArray()); 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /tests/Iterator/ArrayIteratorTest.php: -------------------------------------------------------------------------------- 1 | assertCount(count($array), $iterator); 26 | 27 | $array = [0]; 28 | $iterator = new VectorIterator($array); 29 | 30 | $this->assertCount(count($array), $iterator); 31 | 32 | $array = [0, 2, 4, 6]; 33 | $iterator = new VectorIterator($array); 34 | 35 | $this->assertCount(count($array), $iterator); 36 | } 37 | 38 | /** 39 | * @test 40 | * @dataProvider iteratorProvider 41 | * @param \Iterator $iterator 42 | * @param array $array 43 | */ 44 | public function it_should_iterate_over_iterators(\Iterator $iterator, array $array) 45 | { 46 | $i = 0; 47 | $iterator->rewind(); 48 | while ($i < count($array)) { 49 | $this->assertTrue($iterator->valid()); 50 | $this->assertEquals($i, $iterator->key()); 51 | $this->assertEquals($array[$i], $iterator->current()); 52 | $iterator->next(); 53 | $i++; 54 | } 55 | } 56 | 57 | public function iteratorProvider() 58 | { 59 | $array = [0, 2, 4, 8]; 60 | $array2 = [0, 3]; 61 | 62 | $fnFilter = function ($i) { 63 | return $i >= 0; 64 | }; 65 | 66 | $fnMap = function ($i) { 67 | return $i; 68 | }; 69 | 70 | return [ 71 | [new VectorIterator($array), $array], 72 | [new MapIterator($array), $array], 73 | [new SetIterator($array), $array], 74 | [new PairIterator($array), $array], 75 | [new LazyConcatIterator(new \ArrayIterator($array), new \ArrayIterator($array2)), $array], 76 | [new LazyFilterIterator(new \ArrayIterator($array), $fnFilter), $array], 77 | [new LazyFilterKeyedIterator(new \ArrayIterator($array), $fnFilter), $array], 78 | [new LazyFilterWithKeyIterator(new \ArrayIterator($array), $fnFilter), $array], 79 | [new LazyMapIterator(new \ArrayIterator($array), $fnMap), $array], 80 | [new LazyMapKeyedIterator(new \ArrayIterator($array), $fnMap), $array], 81 | [new LazySkipIterator(new \ArrayIterator($array), 0), $array], 82 | [new LazySkipKeyedIterator(new \ArrayIterator($array), 0), $array] 83 | ]; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tests/MapTest.php: -------------------------------------------------------------------------------- 1 | assertNotNull(new Map([ 21 | 'key1' => 'value1', 22 | 'key2' => [ 23 | 'key21' => 'value21', 24 | 'key22' => [ 25 | 'key221' => 'value221', 26 | ] 27 | ], 28 | 'key3' => 'value3', 29 | 'key4' => 'value4' 30 | ])); 31 | } 32 | 33 | public function testNewInstanceWithTraversable() 34 | { 35 | $traversable = new ArrayObject(array( 36 | 'key1' => 'value1', 37 | 'key2' => 'value2', 38 | 'key3' => 'value3', 39 | 'key4' => 'value4' 40 | )); 41 | $this->assertNotNull(new Map($traversable)); 42 | } 43 | 44 | public function testNewInstance() 45 | { 46 | $this->assertNotNull($this->coll); 47 | } 48 | 49 | /** 50 | * @expectedException \Collections\Exception\InvalidArgumentException 51 | */ 52 | public function testInvalidElementsToInstantiate() 53 | { 54 | $coll = new Map(); 55 | $coll->addAll('string'); 56 | } 57 | 58 | public function testAddAllWithSomeValues() 59 | { 60 | $arrayList = new Map(); 61 | $arrayList 62 | ->add(new Pair('key1', 'value1')) 63 | ->add(new Pair('key2', 'value2')); 64 | 65 | $secoundArrayList = new Map(); 66 | $secoundArrayList 67 | ->add(new Pair('key3', 'value3')) 68 | ->add(new Pair('key4', 'value4')); 69 | 70 | $arrayList->addAll($secoundArrayList); 71 | $this->assertEquals([ 72 | 'key1' => 'value1', 73 | 'key2' => 'value2', 74 | 'key3' => 'value3', 75 | 'key4' => 'value4' 76 | ], $arrayList->toArray()); 77 | } 78 | 79 | public function testContainsKey() 80 | { 81 | $this->coll->set('key', 'value'); 82 | 83 | $this->assertTrue($this->coll->containsKey('key')); 84 | } 85 | 86 | public function testContainsValue() 87 | { 88 | $this->coll->set('key', 'value'); 89 | 90 | $this->assertTrue($this->coll->contains('value')); 91 | } 92 | 93 | public function testAddItem() 94 | { 95 | $this->coll->add(new Pair('key', 'testing')); 96 | $this->assertTrue(is_string((string)$this->coll)); 97 | } 98 | 99 | /** 100 | * @expectedException \Collections\Exception\KeyException 101 | */ 102 | public function testAddDuplicateKey() 103 | { 104 | $this->coll->add(new Pair('key', 'testing')); 105 | $this->coll->add(new Pair('key', 'testing2')); 106 | } 107 | 108 | public function testSetItem() 109 | { 110 | $this->coll->set('key', 'testing'); 111 | $this->assertTrue(is_string((string)$this->coll)); 112 | } 113 | 114 | public function testGetItem() 115 | { 116 | $this->coll->set('keyOne', 'testing'); 117 | $this->assertEquals('testing', $this->coll->get('keyOne')); 118 | } 119 | 120 | /** 121 | * @expectedException \OutOfBoundsException 122 | */ 123 | public function testGetInvalidItem() 124 | { 125 | $this->coll->set('keyOne', 'testing'); 126 | $this->coll->at('keyTwo'); 127 | } 128 | 129 | public function testGetKeys() 130 | { 131 | $this->coll->set('keyOne', 'testing1'); 132 | $this->coll->set('keyTwo', 'testing2'); 133 | $this->coll->set('keyThree', 'testing3'); 134 | 135 | $this->assertEquals(array('keyOne', 'keyTwo', 'keyThree'), $this->coll->toKeysArray()); 136 | } 137 | 138 | public function testTryGetSuccess() 139 | { 140 | $this->coll->set('key', 'testing'); 141 | $value = $this->coll->get('key'); 142 | $this->assertEquals('testing', $value); 143 | } 144 | 145 | public function testTryGetError() 146 | { 147 | $this->coll->add(new Pair('key', 'testing')); 148 | $value = $this->coll->get('key2'); 149 | $this->assertNull($value); 150 | } 151 | 152 | // public function testTryGetDefaultValue() 153 | // { 154 | // $this->coll->set('key', 'testing'); 155 | // $value = $this->coll->get('key2', 'testingValue'); 156 | // $this->assertEquals('testingValue', $value); 157 | // } 158 | 159 | /** 160 | * @expectedException \OutOfBoundsException 161 | */ 162 | public function testRemovingNonExistentKeyReturnsNull() 163 | { 164 | $this->coll->removeKey('testing_does_not_exist'); 165 | } 166 | 167 | /** 168 | * @expectedException \OutOfBoundsException 169 | */ 170 | public function testRemovingNonExistentKey() 171 | { 172 | $this->coll->removeKey('testing_does_not_exist'); 173 | } 174 | 175 | /** 176 | * @expectedException \OutOfBoundsException 177 | */ 178 | public function testRemovingNonExistentElement() 179 | { 180 | $this->coll->remove('testing_does_not_exist'); 181 | } 182 | 183 | public function testArrayAccess() 184 | { 185 | $this->coll['keyOne'] = 'one'; 186 | $this->coll['keyTwo'] = 'two'; 187 | 188 | $this->assertEquals($this->coll['keyOne'], 'one'); 189 | $this->assertEquals($this->coll['keyTwo'], 'two'); 190 | 191 | unset($this->coll['keyOne']); 192 | $this->assertEquals($this->coll->count(), 1); 193 | 194 | $this->assertTrue(isset($this->coll['keyTwo'])); 195 | } 196 | 197 | public function testToList() 198 | { 199 | $this->coll->addAll([ 200 | new Pair("key1", 1), 201 | new Pair("key2", 2), 202 | new Pair("key3", 3), 203 | new Pair("key4", 4) 204 | ]); 205 | $map = $this->coll->toVector(); 206 | 207 | $this->assertInstanceOf(Vector::class, $map); 208 | } 209 | 210 | public function testToArray() 211 | { 212 | $data = [ 213 | new Pair("key1", 'value1'), 214 | new Pair("key2", 'value2'), 215 | new Pair("key3", [ 216 | 'key3.1' => 'value3.1' 217 | ]) 218 | ]; 219 | $this->coll->addAll($data); 220 | $this->assertEquals([ 221 | "key1" => 'value1', 222 | "key2" => 'value2', 223 | "key3" => [ 224 | 'key3.1' => 'value3.1' 225 | ] 226 | ], $this->coll->toArray()); 227 | } 228 | 229 | public function testToValuesArray() 230 | { 231 | $dictionary = new Map(); 232 | $dictionary->set('key1', 'value1')->set('key2', 'value2'); 233 | $expected = ['value1', 'value2']; 234 | $this->assertEquals($expected, $dictionary->toValuesArray()); 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /tests/QueueTest.php: -------------------------------------------------------------------------------- 1 | coll = new Queue(); 21 | } 22 | 23 | public function testNewInstance() 24 | { 25 | $this->assertNotNull($this->coll); 26 | } 27 | 28 | public function testEnqueueItem() 29 | { 30 | $this->coll->enqueue('testing'); 31 | $this->assertTrue(is_string((string)$this->coll)); 32 | } 33 | 34 | public function testEnqueueMultiple() 35 | { 36 | $this->coll->enqueueMultiple(array(1, 2, 3, 4)); 37 | $this->assertTrue(is_string((string)$this->coll)); 38 | } 39 | 40 | /** 41 | * @expectedException RuntimeException 42 | */ 43 | public function testDequeueEmptyQueue() 44 | { 45 | $this->coll->dequeue(); 46 | } 47 | 48 | public function testEnqueueToArray() 49 | { 50 | $this->coll->enqueue('testing1'); 51 | $this->coll->enqueue('testing2'); 52 | $this->coll->enqueue('testing3'); 53 | 54 | $this->assertEquals(array('testing1', 'testing2', 'testing3'), $this->coll->toArray()); 55 | } 56 | 57 | public function testEnqueueAndDequeueToArray() 58 | { 59 | $this->coll->enqueue('testing1'); 60 | $this->coll->enqueue('testing2'); 61 | $this->coll->enqueue('testing3'); 62 | 63 | $this->coll->dequeue(); 64 | 65 | $this->assertEquals(array('testing2', 'testing3'), $this->coll->toArray()); 66 | } 67 | } -------------------------------------------------------------------------------- /tests/SetTest.php: -------------------------------------------------------------------------------- 1 | addAll('string'); 29 | } 30 | 31 | /** 32 | * @test 33 | */ 34 | public function it_should_create_a_new_instance_with_array() 35 | { 36 | $this->assertNotNull(new Set(array( 37 | 1, 38 | 2 => [ 39 | 21, 40 | 22 => [ 41 | 221, 42 | 222 43 | ] 44 | ], 45 | 3, 46 | 4 47 | ))); 48 | } 49 | 50 | /** 51 | * @test 52 | */ 53 | public function it_should_create_a_new_instance_with_traversable() 54 | { 55 | $traversable = new ArrayObject(array( 56 | 1, 57 | 2, 58 | 3, 59 | 4 60 | )); 61 | $this->assertNotNull(new Set($traversable)); 62 | } 63 | 64 | /** 65 | * @test 66 | */ 67 | public function it_should_successfully_add_values() 68 | { 69 | $value = 'test'; 70 | $this->coll->add($value); 71 | $this->assertSame($value, $this->coll->first()); 72 | } 73 | 74 | /** 75 | * @test 76 | * @expectedException \Collections\Exception\ElementAlreadyExists 77 | */ 78 | public function it_should_break_when_add_the_same_value() 79 | { 80 | $value = 'test'; 81 | $this->coll->add($value); 82 | $this->coll->add($value); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /tests/StackTest.php: -------------------------------------------------------------------------------- 1 | coll = new Stack(); 26 | } 27 | 28 | public function testNewInstance() 29 | { 30 | $this->assertNotNull($this->coll); 31 | } 32 | 33 | public function testEnqueueItem() 34 | { 35 | $this->coll->push('testing'); 36 | $this->assertTrue(is_string((string)$this->coll)); 37 | } 38 | 39 | public function testEnqueueMultiple() 40 | { 41 | $this->coll->pushMultiple(array(1, 2, 3, 4)); 42 | $this->assertTrue(is_string((string)$this->coll)); 43 | } 44 | 45 | /** 46 | * @expectedException RuntimeException 47 | */ 48 | public function testDequeueEmptyQueue() 49 | { 50 | $this->coll->pop(); 51 | } 52 | 53 | public function testEnqueueToArray() 54 | { 55 | $this->coll->push('testing1'); 56 | $this->coll->push('testing2'); 57 | $this->coll->push('testing3'); 58 | 59 | $this->assertEquals(array('testing1', 'testing2', 'testing3'), $this->coll->toArray()); 60 | } 61 | 62 | public function testEnqueueAndDequeueToArray() 63 | { 64 | $this->coll->push('testing1'); 65 | $this->coll->push('testing2'); 66 | $this->coll->push('testing3'); 67 | 68 | $this->coll->pop(); 69 | 70 | $this->assertEquals(array('testing1', 'testing2'), $this->coll->toArray()); 71 | } 72 | } -------------------------------------------------------------------------------- /tests/VectorTest.php: -------------------------------------------------------------------------------- 1 | addAll('string'); 24 | } 25 | 26 | public function testNewInstanceWithArray() 27 | { 28 | $this->assertNotNull(new Vector([ 29 | 1, 30 | 2 => [ 31 | 21, 32 | 22 => [ 33 | 221, 34 | 222 35 | ] 36 | ], 37 | 3, 38 | 4 39 | ])); 40 | } 41 | 42 | public function testNewInstanceWithTraversable() 43 | { 44 | $traversable = new ArrayObject(range(1, 4)); 45 | $this->assertNotNull(new Vector($traversable)); 46 | } 47 | 48 | public function testNewInstance() 49 | { 50 | $this->assertNotNull($this->coll); 51 | } 52 | 53 | /** 54 | * @test 55 | */ 56 | public function it_should_create_vector_from_items() 57 | { 58 | $data = range(1, 10); 59 | $vector = Vector::fromItems($data); 60 | 61 | $this->assertNotNull($vector); 62 | } 63 | 64 | public function testAddAllWithSomeValues() 65 | { 66 | $arrayList = new Vector(); 67 | $arrayList 68 | ->add(1) 69 | ->add(2); 70 | 71 | $secoundArrayList = new Vector(); 72 | $secoundArrayList 73 | ->add(3) 74 | ->add(new Vector([31])); 75 | 76 | $arrayList->addAll($secoundArrayList); 77 | 78 | $this->assertEquals([ 79 | 0 => 1, 80 | 1 => 2, 81 | 2 => 3, 82 | 3 => [ 83 | 0 => 31 84 | ] 85 | ], $arrayList->toArray()); 86 | } 87 | 88 | public function testToString() 89 | { 90 | $this->coll->add('testing'); 91 | $this->assertTrue(is_string((string)$this->coll)); 92 | } 93 | 94 | public function testGetValueByIndex() 95 | { 96 | $value = 'testing'; 97 | 98 | $this->coll->add($value); 99 | $this->assertSame($value, $this->coll->get(0)); 100 | } 101 | 102 | 103 | public function testSort() 104 | { 105 | $this->coll->add('testing'); 106 | $this->coll->sort(); 107 | $this->assertTrue(is_array($this->coll->toArray())); 108 | } 109 | 110 | public function testSortByKey() 111 | { 112 | $this->coll->add('testing'); 113 | $this->coll->sortByKey(); 114 | $this->assertTrue(is_array($this->coll->toArray())); 115 | } 116 | 117 | public function testRemovingValueReturnsTrue() 118 | { 119 | $element = 'testing'; 120 | $this->coll->add($element); 121 | 122 | $key = $this->coll->indexOf($element); 123 | $this->coll->removeKey($key); 124 | 125 | $this->assertFalse($this->coll->containsKey($key)); 126 | } 127 | 128 | /** 129 | * @expectedException \OutOfBoundsException 130 | */ 131 | public function testRemovingValueThrowsException() 132 | { 133 | $element = 'testing'; 134 | $this->coll->add($element); 135 | $this->coll->removeKey(-1); 136 | } 137 | 138 | /** 139 | * @expectedException \Collections\Exception\TypeException 140 | */ 141 | public function testRemovingWrongType() 142 | { 143 | $this->coll->removeKey('testing_does_not_exist'); 144 | } 145 | 146 | public function testEquals() 147 | { 148 | $this->assertTrue($this->coll->equals($this->coll)); 149 | } 150 | 151 | public function testNotEquals() 152 | { 153 | $this->assertFalse($this->coll->equals(new Vector())); 154 | } 155 | 156 | public function testInteratorInsntance() 157 | { 158 | $this->assertInstanceOf('\ArrayIterator', $this->coll->getIterator()); 159 | } 160 | 161 | public function testSerialize() 162 | { 163 | $this->coll->add('testing1'); 164 | $this->coll->add('testing2'); 165 | $this->assertNotEmpty($this->coll->serialize()); 166 | } 167 | 168 | public function testUnserialize() 169 | { 170 | $this->coll->add('testing1'); 171 | $this->coll->add('testing2'); 172 | $this->assertNotEmpty($this->coll->unserialize($this->coll->serialize())); 173 | } 174 | 175 | public function testSetComparer() 176 | { 177 | $this->assertNotNull($this->coll->setDefaultComparer(new StringComparer())); 178 | } 179 | 180 | public function testContains() 181 | { 182 | $this->coll->add("one"); 183 | $this->coll->add("two"); 184 | 185 | $key = $this->coll->indexOf("one"); 186 | 187 | $exists = $this->coll->containsKey($key); 188 | $this->assertTrue($exists); 189 | } 190 | 191 | /** 192 | * @expectedException \Collections\Exception\TypeException 193 | */ 194 | public function testContainsWithWrongKeyType() 195 | { 196 | $this->coll->add("one"); 197 | $this->coll->containsKey("other"); 198 | } 199 | 200 | public function testExists() 201 | { 202 | $this->coll->add("one"); 203 | $this->coll->add("two"); 204 | $exists = $this->coll->exists(function ($e) { 205 | return $e == "one"; 206 | }); 207 | $this->assertTrue($exists); 208 | $exists = $this->coll->exists(function ($e) { 209 | return $e == "other"; 210 | }); 211 | $this->assertFalse($exists); 212 | } 213 | 214 | public function testArrayAccess() 215 | { 216 | $this->coll[0] = 'one'; 217 | $this->coll[1] = 'two'; 218 | 219 | $this->assertEquals($this->coll[0], 'one'); 220 | $this->assertEquals($this->coll[1], 'two'); 221 | 222 | $this->assertTrue(isset($this->coll[1])); 223 | } 224 | 225 | /** 226 | * @expectedException \RuntimeException 227 | */ 228 | public function testTryToUnsetAnElement() 229 | { 230 | $this->coll[0] = 'one'; 231 | unset($this->coll[0]); 232 | } 233 | 234 | /** 235 | * @expectedException \Collections\Exception\TypeException 236 | */ 237 | public function testInvalidOffsetExists() 238 | { 239 | $this->coll[1] = 'one'; 240 | $this->assertFalse(isset($this->coll['string'])); 241 | } 242 | 243 | /** 244 | * @expectedException \Collections\Exception\TypeException 245 | */ 246 | public function testInvalidOffsetSet() 247 | { 248 | $this->coll['string'] = 'one'; 249 | } 250 | 251 | public function testSearch() 252 | { 253 | $this->coll[0] = 'test'; 254 | $this->assertEquals(0, $this->coll->indexOf('test')); 255 | } 256 | 257 | public function testCount() 258 | { 259 | $this->coll[0] = 'one'; 260 | $this->coll[1] = 'two'; 261 | $this->assertEquals($this->coll->count(), 2); 262 | $this->assertEquals(count($this->coll), 2); 263 | } 264 | 265 | public function testClear() 266 | { 267 | $this->coll[0] = 'one'; 268 | $this->coll[1] = 'two'; 269 | $this->coll->clear(); 270 | $this->assertEquals($this->coll->isEmpty(), true); 271 | } 272 | 273 | public function testToMap() 274 | { 275 | $this->coll->addAll(range(1, 4)); 276 | $map = $this->coll->toMap(); 277 | 278 | $this->assertInstanceOf(Map::class, $map); 279 | } 280 | 281 | public function testReduce() 282 | { 283 | $this->coll->addAll(range(1, 4)); 284 | $result = $this->coll->reduce(function ($carry, $item) { 285 | return $carry += $item; 286 | }); 287 | 288 | $this->assertEquals(10, $result); 289 | 290 | $result = $this->coll->reduce(function ($carry, $item) { 291 | return $carry += $item; 292 | }, 10); 293 | 294 | $this->assertEquals(20, $result); 295 | } 296 | 297 | /** 298 | * @test 299 | */ 300 | public function it_should_reverse_the_collection() 301 | { 302 | $coll = new Vector(range(1, 5)); 303 | 304 | $this->assertSame([ 305 | 5, 306 | 4, 307 | 3, 308 | 2, 309 | 1 310 | ], $coll->reverse()->toArray()); 311 | } 312 | } 313 | --------------------------------------------------------------------------------