From e59b29b641a929c8742f274165007e9a24b658d3 Mon Sep 17 00:00:00 2001 From: Pol Dellaiera Date: Sun, 22 Aug 2021 22:41:47 +0200 Subject: [PATCH] refactor: Update `Window` operation in point free style. (#179) * refactor: Update Window operation in point free style. * docs: Update Window operation documentation. * fix: Fix SA return types. * fix: Fix minor typo. * tests: Add/update window operation tests. * Autofix CS. --- docs/pages/api.rst | 12 +-- docs/pages/code/operations/window.php | 28 +++++ spec/loophp/collection/CollectionSpec.php | 122 +++------------------- src/Contract/Operation/Windowable.php | 2 +- src/Operation/Window.php | 39 +++---- 5 files changed, 66 insertions(+), 137 deletions(-) create mode 100644 docs/pages/code/operations/window.php diff --git a/docs/pages/api.rst b/docs/pages/api.rst index 6ca3c1b92..2b65b2f06 100644 --- a/docs/pages/api.rst +++ b/docs/pages/api.rst @@ -2439,16 +2439,16 @@ window Loop the collection yielding windows of data by adding a given number of items to the current item. Initially the windows yielded will be smaller, until size ``1 + $size`` is reached. -Interface: `Windowable`_ +.. tip:: To remove the window size constraint and have a dynamic window size, set the ``$size`` to ``-1``. -Signature: ``Collection::window(int $size): Collection;`` +.. note:: When ``$size`` is equal to ``0``, the window will only contain the current element, wrapped in an array. -.. code-block:: php +Interface: `Windowable`_ - $data = range('a', 'd'); +Signature: ``Collection::window(int $size): Collection;`` - Collection::fromIterable($data) - ->window(2); // [['a'], ['a', 'b'], ['a', 'b', 'c'], ['b', 'c', 'd']] +.. literalinclude:: code/operations/window.php + :language: php words ~~~~~ diff --git a/docs/pages/code/operations/window.php b/docs/pages/code/operations/window.php new file mode 100644 index 000000000..7180219de --- /dev/null +++ b/docs/pages/code/operations/window.php @@ -0,0 +1,28 @@ +window(0); // [['a'], ['b'], ['c'], ['d'], ['e']] + +Collection::fromIterable($data) + ->window(1); // [['a'], ['a', 'b'], ['b', 'c'], ['c', 'd'], ['d', 'e']] + +Collection::fromIterable($data) + ->window(2); // [['a'], ['a', 'b'], ['a', 'b', 'c'], ['b', 'c', 'd'], ['c', 'd', 'e']] + +Collection::fromIterable($data) + ->window(-1); // [['a'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd', 'e']] diff --git a/spec/loophp/collection/CollectionSpec.php b/spec/loophp/collection/CollectionSpec.php index 68dec11be..88fd9b0c3 100644 --- a/spec/loophp/collection/CollectionSpec.php +++ b/spec/loophp/collection/CollectionSpec.php @@ -4012,11 +4012,15 @@ public function it_can_when(): void public function it_can_window(): void { - $this::fromIterable(range('a', 'z')) + $this::fromIterable(['a' => 'A', 'b' => 'B', 'c' => 'C']) ->window(0) - ->shouldIterateAs(range('a', 'z')); + ->shouldIterateAs([ + 'a' => ['A'], + 'b' => ['B'], + 'c' => ['C'], + ]); - $this::fromIterable(range('a', 'z')) + $this::fromIterable(range('a', 'e')) ->window(2) ->shouldIterateAs([ 0 => [ @@ -4041,111 +4045,13 @@ public function it_can_window(): void 1 => 'd', 2 => 'e', ], - 5 => [ - 0 => 'd', - 1 => 'e', - 2 => 'f', - ], - 6 => [ - 0 => 'e', - 1 => 'f', - 2 => 'g', - ], - 7 => [ - 0 => 'f', - 1 => 'g', - 2 => 'h', - ], - 8 => [ - 0 => 'g', - 1 => 'h', - 2 => 'i', - ], - 9 => [ - 0 => 'h', - 1 => 'i', - 2 => 'j', - ], - 10 => [ - 0 => 'i', - 1 => 'j', - 2 => 'k', - ], - 11 => [ - 0 => 'j', - 1 => 'k', - 2 => 'l', - ], - 12 => [ - 0 => 'k', - 1 => 'l', - 2 => 'm', - ], - 13 => [ - 0 => 'l', - 1 => 'm', - 2 => 'n', - ], - 14 => [ - 0 => 'm', - 1 => 'n', - 2 => 'o', - ], - 15 => [ - 0 => 'n', - 1 => 'o', - 2 => 'p', - ], - 16 => [ - 0 => 'o', - 1 => 'p', - 2 => 'q', - ], - 17 => [ - 0 => 'p', - 1 => 'q', - 2 => 'r', - ], - 18 => [ - 0 => 'q', - 1 => 'r', - 2 => 's', - ], - 19 => [ - 0 => 'r', - 1 => 's', - 2 => 't', - ], - 20 => [ - 0 => 's', - 1 => 't', - 2 => 'u', - ], - 21 => [ - 0 => 't', - 1 => 'u', - 2 => 'v', - ], - 22 => [ - 0 => 'u', - 1 => 'v', - 2 => 'w', - ], - 23 => [ - 0 => 'v', - 1 => 'w', - 2 => 'x', - ], - 24 => [ - 0 => 'w', - 1 => 'x', - 2 => 'y', - ], - 25 => [ - 0 => 'x', - 1 => 'y', - 2 => 'z', - ], + ]); + + // Unsupported - but tested. + $this::fromIterable(range('a', 'e')) + ->window(-2) + ->shouldIterateAs([ + [], [], [], [], [], ]); } diff --git a/src/Contract/Operation/Windowable.php b/src/Contract/Operation/Windowable.php index 71f69e153..3552d477d 100644 --- a/src/Contract/Operation/Windowable.php +++ b/src/Contract/Operation/Windowable.php @@ -19,7 +19,7 @@ interface Windowable { /** * Loop the collection yielding windows of data by adding a given number of items to the current item. - * Initially the windows yielded will be smaller, until size` 1 + $size` is reached. + * Initially the windows yielded will be smaller, until size `1 + $size` is reached. * * @see https://loophp-collection.readthedocs.io/en/stable/pages/api.html#window * diff --git a/src/Operation/Window.php b/src/Operation/Window.php index ff16524b9..335c3513b 100644 --- a/src/Operation/Window.php +++ b/src/Operation/Window.php @@ -26,33 +26,28 @@ final class Window extends AbstractOperation /** * @pure * - * @return Closure(int): Closure(Iterator): Generator> + * @return Closure(int): Closure(Iterator): Generator> */ public function __invoke(): Closure { return /** - * @return Closure(Iterator): Generator> + * @return Closure(Iterator): Generator> */ - static fn (int $size): Closure => - /** - * @param Iterator $iterator - * - * @return Generator|T> - */ - static function (Iterator $iterator) use ($size): Generator { - if (0 === $size) { - return yield from $iterator; - } - - ++$size; - $size *= -1; - - $stack = []; - - foreach ($iterator as $key => $current) { - yield $key => $stack = array_slice([...$stack, $current], $size); - } - }; + static function (int $size): Closure { + /** @var Closure(Iterator): Generator> $reduction */ + $reduction = Reduction::of()( + /** + * @param list $stack + * @param T $current + * + * @return list + */ + static fn (array $stack, $current): array => array_slice([...$stack, $current], ++$size * -1) + )([]); + + // Point free style. + return $reduction; + }; } }