{"id":16904434,"url":"https://github.com/crell/orderedcollection","last_synced_at":"2025-04-11T14:32:56.983Z","repository":{"id":147535198,"uuid":"618873902","full_name":"Crell/OrderedCollection","owner":"Crell","description":"A fast and robust library for priority and topological sorting.","archived":false,"fork":false,"pushed_at":"2024-09-25T13:53:17.000Z","size":88,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-19T00:04:18.232Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Crell.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":["Crell"]}},"created_at":"2023-03-25T15:50:10.000Z","updated_at":"2024-09-25T13:53:17.000Z","dependencies_parsed_at":"2023-12-02T02:25:04.398Z","dependency_job_id":"d6ba9052-0b62-4417-9953-f1172072633f","html_url":"https://github.com/Crell/OrderedCollection","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Crell%2FOrderedCollection","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Crell%2FOrderedCollection/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Crell%2FOrderedCollection/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Crell%2FOrderedCollection/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Crell","download_url":"https://codeload.github.com/Crell/OrderedCollection/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248419760,"owners_count":21100246,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T18:33:22.044Z","updated_at":"2025-04-11T14:32:56.957Z","avatar_url":"https://github.com/Crell.png","language":"PHP","funding_links":["https://github.com/sponsors/Crell"],"categories":[],"sub_categories":[],"readme":"# Ordered Collection\n\n[![Latest Version on Packagist][ico-version]][link-packagist]\n[![Software License][ico-license]](LICENSE.md)\n[![Total Downloads][ico-downloads]][link-downloads]\n\nOrdered Collection is what it says on the tin; it's a flexible tool for ordering arbitrary items based on either priority values or topological sorting (before/after).  It contains two implementations, `OrderedCollection` and `MultiOrderedCollection`.  The former is a bit faster, while the latter is considerably more powerful.\n\nFor more on Priority and Topological sorting, see [this benchmark blog post](https://peakd.com/hive-168588/@crell/extrinsic-sorting-benchmark) comparing the results.\n\n## `OrderedCollection`\n\n`OrderedCollection` supports ordering items by integer priorities, or a single before/after value.  Internally, it converts the before/after information into priority values, and then sorts the whole list by priority.  This is often faster than sorting topologically, but does not handle more than a single before/after entry per item, and cannot detect cyclic dependencies in the before/after ordering.\n\nTo use it first, create a new collection:\n\n```php\nuse Crell\\OrderedCollection\\OrderedCollection;\n\n$collection = new OrderedCollection();\n```\n\nNow, arbitrary items may be added to the collection with `addItem()`, `addItemBefore()`, and `addItemAfter()`.  Each item may be an arbitrary value, and they do not need to be of the same type.\n\nWhen adding an item, you may provide an `$id`.  If you do not, one will be created on the fly.  The ID that was used will be returned by the `addItem*()` method.  The ID is necessary for before/after ordering.  If the ID is already in use, a numeric suffix will be added automatically to ensure uniqueness.\n\n```php\n// Adds an item with priority 3, and a random ID will be generated.\n$kirk = $collection-\u003eaddItem('James T. Kirk', 3);\n\n// Adds an item with priority 5, and an ID of \"picard\".\n$picard = $collection-\u003eaddItem('Jean-Luc Picard', 5, 'picard');\n\n// Adds an item to some somewhere after another item, by its ID. \n// The ID for it will be auto-generated\n$sisko = $collection-\u003eaddItemAfter($picard, 'Benjamin Sisko');\n\n// Adds an item to some somewhere before another item, by its ID.\n// The new item's ID will be \"janeway\".\n$janeway = $collection-\u003eaddItemBefore($kirk, 'Katheryn Janeway', 'janeway');\n```\n\nOnce the items are added, they will be sorted automatically the first time the collection is iterated.  `OrderedCollection` implements `\\IteratorAggregate`, so you can use either `foreach()` or `iterator_to_array()` to get values back out.\n\n```php\nforeach ($collection as $item) {\n    print $item . PHP_EOL;\n}\n```\n\nIn this case, would give the following output:\n\n```text\nKatheryn Janeway\nJean-Luc Picard\nBenjamin Sisko\nJames T. Kirk\n```\n\n## `MultiOrderedCollection`\n\nThis second, more robust option is very similar to `OrderedCollection`, and both implement the same `OrderableCollection` interface.  However, `MultiOrderedCollection` has an additional method, `add()`, that can handle priority, before, and after ordering, and supports multiple before/after entries on the same item.  For that reason, using `add()` with `MultiOrderedCollection` is recommended, though the common interface will still work on both.\n\n`MultiOrderedCollection` converts all priorities into \"before\" entries, and then sorts the collection topologically.  This can be a little bit slower, but it supports multiple before/after directives on a single item and will also detect circular dependencies, which triggers a `CycleFound` exception.\n\nThe `add()` method's signature is like so:\n\n```php\nadd(\n    mixed $item,\n    ?string $id = null,\n    ?int $priority = null,\n    array $before = [],\n    array $after = [],\n): string\n```\n\nThe return value is the ID that was assigned to the value, which may then be used in before/after ordering.  Of note, the `$before` and `$after` parameters take an array, not a single ID.  Also, because there are so many options, using named arguments is strongly recommended.\n\nThe example above, on `MultiOrderedCollection`, would look like this:\n\n```php\nuse Crell\\OrderedCollection\\MultiOrderedCollection;\n\n$collection = new MultiOrderedCollection();\n\n// Adds an item with priority 3, and a random ID will be generated.\n$kirk = $collection-\u003eadd('James T. Kirk', priority: 3);\n\n// Adds an item with priority 3, and an ID of \"picard\".\n$picard = $collection-\u003eadd('Jean-Luc Picard', priority: 5, id: 'picard');\n\n// Adds an item to some somewhere after another item, by its ID.\n// The ID for it will be auto-generated\n$sisko = $collection-\u003eadd('Benjamin Sisko', after: ['picard']);\n\n// Adds an item to some somewhere before another item, by its ID.\n// The new item's ID will be \"janeway\".\n$janeway = $collection-\u003eadd('Katheryn Janeway', before: [$kirk], id: 'janeway');\n\nforeach ($collection as $item) {\n    print $item . PHP_EOL;\n}\n```\n\nIn this case, the output would be the same as before.\n\n```text\nKatheryn Janeway\nJean-Luc Picard\nBenjamin Sisko\nJames T. Kirk\n```\n\n## Guarantees\n\n`OrderedCollection` and `MultiOrderedCollection` provide the following guarantees about the resulting list of values \nreturned:\n\n* Any item with a higher priority integer will come before an item with a lower priority integer.\n* Any item listed as \"before\" another item will come before that item.\n* Any item listed as \"after\" another item will come after that item.\n\nThey do not provide the following guarantees, so while they may happen you should not count on them.\n\n * An item that comes \"before\" another may not come immediately before.  There could still be other items that come between them.\n * An item that comes \"after\" another may not come immediately after.  There could still be other items that come between them.\n * The order in which items are added is irrelevant.  With `OrderedCollection`, items that have the same priority \n   will *usually* be returned in the order in which they were added, but that is not guaranteed.  With `MultiOrderedCollection`, they will most likely not be returned in the order they were added.  In short, if you care about the order at all, specify it explicitly.\n\n## Types\n\nThe items being sorted are not used at all during the process.  While the example above shows strings, you can use arrays, objects, strings, numbers, or whatever else you'd like.  They may be of the same type, or different types.  The collection objects don't care.\n\n## Change log\n\nPlease see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.\n\n## Testing\n\n``` bash\n$ composer test\n```\n\n## Contributing\n\nPlease see [CONTRIBUTING](CONTRIBUTING.md) and [CODE_OF_CONDUCT](CODE_OF_CONDUCT.md) for details.\n\n## Security\n\nIf you discover any security related issues, please use the [GitHub security reporting form](https://github.com/Crell/OrderedCollection/security) rather than the issue queue.\n\n## Credits\n\n- [Larry Garfield][link-author]\n- [All Contributors][link-contributors]\n\n## License\n\nThe Lesser GPL version 3 or later. Please see [License File](LICENSE.md) for more information.\n\n[ico-version]: https://img.shields.io/packagist/v/Crell/OrderedCollection.svg?style=flat-square\n[ico-license]: https://img.shields.io/badge/License-LGPLv3-green.svg?style=flat-square\n[ico-downloads]: https://img.shields.io/packagist/dt/Crell/OrderedCollection.svg?style=flat-square\n\n[link-packagist]: https://packagist.org/packages/crell/ordered-collection\n[link-downloads]: https://packagist.org/packages/crell/ordered-collection\n[link-author]: https://github.com/Crell\n[link-contributors]: ../../contributors\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrell%2Forderedcollection","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcrell%2Forderedcollection","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcrell%2Forderedcollection/lists"}