From b8f8ba41889f3835a261105ba70c61b63dec8319 Mon Sep 17 00:00:00 2001 From: Adrian Panicek Date: Fri, 18 Dec 2020 19:17:26 +0100 Subject: [PATCH] Adding key_sort functionality --- composer.json | 1 + src/Functional/Functional.php | 5 ++ src/Functional/KeySort.php | 44 +++++++++++++++ tests/Functional/KeySortTest.php | 94 ++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 src/Functional/KeySort.php create mode 100644 tests/Functional/KeySortTest.php diff --git a/composer.json b/composer.json index 6017cf63..0e701d67 100644 --- a/composer.json +++ b/composer.json @@ -67,6 +67,7 @@ "src/Functional/InvokeIf.php", "src/Functional/InvokeLast.php", "src/Functional/Invoker.php", + "src/Functional/KeySort.php", "src/Functional/Last.php", "src/Functional/LastIndexOf.php", "src/Functional/LessThan.php", diff --git a/src/Functional/Functional.php b/src/Functional/Functional.php index 845faa6c..ca4bbf7b 100644 --- a/src/Functional/Functional.php +++ b/src/Functional/Functional.php @@ -223,6 +223,11 @@ final class Functional */ const invoker = '\Functional\invoker'; + /** + * @see \Functional\key_sort + */ + const key_sort = '\Functional\key_sort'; + /** * @see \Functional\last */ diff --git a/src/Functional/KeySort.php b/src/Functional/KeySort.php new file mode 100644 index 00000000..59c2d246 --- /dev/null +++ b/src/Functional/KeySort.php @@ -0,0 +1,44 @@ + + * @license https://opensource.org/licenses/MIT MIT + * @link https://github.com/adrianpanicek/functional-php + */ + +namespace Functional; + +use Traversable; +use Functional\Exceptions\InvalidArgumentException; + +/** + * Sort collection by array keys + * + * @param Traversable|array $collection + * @param callable|null $callback + * + * @return array + */ +function key_sort($collection, callable $callback = null) +{ + InvalidArgumentException::assertCollection($collection, __FUNCTION__, 1); + + if ($collection instanceof Traversable) { + $array = \iterator_to_array($collection); + } else { + $array = $collection; + } + + if ($callback === null) { + \ksort($array); + + return $array; + } + + \uksort($array, static function ($a, $b) use ($callback, $array) { + return $callback($a, $b, $array); + }); + + return $array; +} diff --git a/tests/Functional/KeySortTest.php b/tests/Functional/KeySortTest.php new file mode 100644 index 00000000..b382d992 --- /dev/null +++ b/tests/Functional/KeySortTest.php @@ -0,0 +1,94 @@ + + * @license https://opensource.org/licenses/MIT MIT + * @link https://github.com/adrianpanicek/functional-php + */ + +namespace Functional\Tests; + +use ArrayIterator; +use Functional as F; +use Functional\Exceptions\InvalidArgumentException; + +use function Functional\key_sort; + +class KeySortTest extends AbstractTestCase +{ + public function setUp() + { + parent::setUp(); + $this->list = ['cat', 'bear', 'aardvark']; + $this->listIterator = new ArrayIterator($this->list); + $this->hash = ['c' => 'cat', 'b' => 'bear', 'a' => 'aardvark']; + $this->hashIterator = new ArrayIterator($this->hash); + $this->ksortCallback = function ($left, $right, $collection) { + InvalidArgumentException::assertCollection($collection, __FUNCTION__, 3); + return strcmp($left, $right); + }; + } + + public function testWithoutCallback() + { + $this->assertSame(['cat', 'bear', 'aardvark'], F\key_sort($this->list)); + $this->assertSame(['cat', 'bear', 'aardvark'], F\key_sort($this->listIterator)); + $this->assertSame(['a' => 'aardvark', 'b' => 'bear', 'c' => 'cat'], F\key_sort($this->hash)); + $this->assertSame(['a' => 'aardvark', 'b' => 'bear', 'c' => 'cat'], F\key_sort($this->hashIterator)); + } + + public function testWithCallback() + { + $this->assertSame(['cat', 'bear', 'aardvark'], F\key_sort($this->list, $this->ksortCallback)); + $this->assertSame(['cat', 'bear', 'aardvark'], F\key_sort($this->listIterator, $this->ksortCallback)); + $this->assertSame(['a' => 'aardvark', 'b' => 'bear', 'c' => 'cat'], F\key_sort($this->hash, $this->ksortCallback)); + $this->assertSame(['a' => 'aardvark', 'b' => 'bear', 'c' => 'cat'], F\key_sort($this->hashIterator, $this->ksortCallback)); + } + + public function testImmutability() + { + F\key_sort($this->hash); + $this->assertSame(['c' => 'cat', 'b' => 'bear', 'a' => 'aardvark'], $this->hash); + } + + public function testPassNonCallable() + { + $this->expectArgumentError("Argument 2 passed to Functional\key_sort() must be callable or null"); + F\key_sort($this->list, 'undefinedFunction'); + } + + public function testPassNoCollection() + { + $this->expectArgumentError('key_sort() expects parameter 1 to be array or instance of Traversable'); + F\key_sort('invalidCollection', 'strlen'); + } + + public function testExceptionIsThrownInArray() + { + $this->expectException('DomainException'); + $this->expectExceptionMessage('Callback exception'); + F\key_sort($this->list, [$this, 'exception']); + } + + public function testExceptionIsThrownInHash() + { + $this->expectException('DomainException'); + $this->expectExceptionMessage('Callback exception'); + F\key_sort($this->hash, [$this, 'exception']); + } + + public function testExceptionIsThrownInIterator() + { + $this->expectException('DomainException'); + $this->expectExceptionMessage('Callback exception'); + F\key_sort($this->listIterator, [$this, 'exception']); + } + + public function testExceptionIsThrownInHashIterator() + { + $this->expectException('DomainException'); + $this->expectExceptionMessage('Callback exception'); + F\key_sort($this->hashIterator, [$this, 'exception']); + } +}