diff --git a/docs/pages/api.rst b/docs/pages/api.rst index 3d701bb73..c89aa2dbc 100644 --- a/docs/pages/api.rst +++ b/docs/pages/api.rst @@ -463,6 +463,25 @@ Signature: ``Collection::distinct();`` $collection = Collection::with(['a', 'b', 'c', 'd', 'a']) ->distinct() +dropWhile +~~~~~~~~~ + +It inspects the original collection and takes from it its elements from the moment when the condition fails for the +first time till the end of the list. + +Interface: `DropWhileable`_ + +Signature: ``Collection::dropWhile(callable $callback);`` + +.. code-block:: php + + $isSmallerThanThree = static function (int $value): bool { + return 3 > $value; + }; + + Collection::fromIterable([1,2,3,4,5,6,7,8,9,1,2,3]) + ->dropWhile($isSmallerThanThree); // [3,4,5,6,7,8,9,1,2,3] + explode ~~~~~~~ @@ -1558,6 +1577,7 @@ Signature: ``Collection::zip(iterable ...$iterables);`` .. _Diffable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Diffable.php .. _Diffkeysable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Diffkeysable.php .. _Distinctable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Distinctable.php +.. _DropWhileable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/DropWhileable.php .. _Explodeable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Explodeable.php .. _Falsyable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Falsyable.php .. _Filterable: https://github.com/loophp/collection/blob/master/src/Contract/Operation/Filterable.php diff --git a/spec/loophp/collection/CollectionSpec.php b/spec/loophp/collection/CollectionSpec.php index b5663dff3..d9b784c04 100644 --- a/spec/loophp/collection/CollectionSpec.php +++ b/spec/loophp/collection/CollectionSpec.php @@ -543,6 +543,28 @@ public function it_can_do_the_cartesian_product(): void ->shouldIterateAs([0 => ['A', 1], 1 => ['A', 2], 2 => ['B', 1], 3 => ['B', 2], 4 => ['C', 1], 5 => ['C', 2]]); } + public function it_can_dropWhile(): void + { + $isSmallerThanThree = static function ($value) { + return 3 > $value; + }; + + $this::fromIterable([1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3]) + ->dropWhile($isSmallerThanThree) + ->shouldIterateAs([ + 2 => 3, + 3 => 4, + 4 => 5, + 5 => 6, + 6 => 7, + 7 => 8, + 8 => 9, + 9 => 1, + 10 => 2, + 11 => 3, + ]); + } + public function it_can_explode(): void { $string = 'I am just a random piece of text.'; diff --git a/src/Collection.php b/src/Collection.php index 253a293fc..b461e33a5 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -29,6 +29,7 @@ use loophp\collection\Operation\Diff; use loophp\collection\Operation\DiffKeys; use loophp\collection\Operation\Distinct; +use loophp\collection\Operation\DropWhile; use loophp\collection\Operation\Explode; use loophp\collection\Operation\Falsy; use loophp\collection\Operation\Filter; @@ -324,6 +325,11 @@ public function distinct(): CollectionInterface return $this->run(Distinct::of()); } + public function dropWhile(callable $callback): CollectionInterface + { + return $this->run(DropWhile::of()($callback)); + } + public static function empty(): Collection { return new self(); diff --git a/src/Contract/Collection.php b/src/Contract/Collection.php index 5023c5d0a..3df5bfca2 100644 --- a/src/Contract/Collection.php +++ b/src/Contract/Collection.php @@ -23,6 +23,7 @@ use loophp\collection\Contract\Operation\Diffable; use loophp\collection\Contract\Operation\Diffkeysable; use loophp\collection\Contract\Operation\Distinctable; +use loophp\collection\Contract\Operation\DropWhileable; use loophp\collection\Contract\Operation\Explodeable; use loophp\collection\Contract\Operation\Falsyable; use loophp\collection\Contract\Operation\Filterable; @@ -109,6 +110,7 @@ * @template-extends Diffable<TKey, T> * @template-extends Diffkeysable<TKey, T> * @template-extends Distinctable<TKey, T> + * @template-extends DropWhileable<TKey, T> * @template-extends Explodeable<TKey, T> * @template-extends Filterable<TKey, T> * @template-extends Firstable<TKey, T> @@ -185,6 +187,7 @@ interface Collection extends Diffable, Diffkeysable, Distinctable, + DropWhileable, Explodeable, Falsyable, Filterable, diff --git a/src/Contract/Operation/DropWhileable.php b/src/Contract/Operation/DropWhileable.php new file mode 100644 index 000000000..78abd0a37 --- /dev/null +++ b/src/Contract/Operation/DropWhileable.php @@ -0,0 +1,20 @@ +<?php + +declare(strict_types=1); + +namespace loophp\collection\Contract\Operation; + +use loophp\collection\Contract\Collection; + +/** + * @psalm-template TKey + * @psalm-template TKey of array-key + * @psalm-template T + */ +interface DropWhileable +{ + /** + * @psalm-return \loophp\collection\Contract\Collection<TKey, T> + */ + public function dropWhile(callable $callback): Collection; +} diff --git a/src/Operation/DropWhile.php b/src/Operation/DropWhile.php new file mode 100644 index 000000000..0d29a42c4 --- /dev/null +++ b/src/Operation/DropWhile.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +namespace loophp\collection\Operation; + +use Closure; +use Generator; +use Iterator; + +/** + * @psalm-template TKey + * @psalm-template TKey of array-key + * @psalm-template T + * + * phpcs:disable Generic.Files.LineLength.TooLong + */ +final class DropWhile extends AbstractOperation +{ + /** + * @psalm-return Closure((callable(T, TKey, Iterator<TKey, T>): bool)): Closure(Iterator<TKey, T>): Generator<TKey, T> + */ + public function __invoke(): Closure + { + return + /** + * @psalm-param callable(T, TKey, Iterator<TKey, T>):bool $callback + * + * @psalm-return Closure(Iterator<TKey, T>): Generator<TKey, T> + */ + static function (callable $callback): Closure { + return + /** + * @psalm-param Iterator<TKey, T> $iterator + * + * @psalm-return Generator<TKey, T> + */ + static function (Iterator $iterator) use ($callback): Generator { + for (; $iterator->valid(); $iterator->next()) { + if (true === $callback($iterator->current(), $iterator->key(), $iterator)) { + continue; + } + + break; + } + + for (; $iterator->valid(); $iterator->next()) { + yield $iterator->key() => $iterator->current(); + } + }; + }; + } +}